Brighter: Handler Assíncronos

Introdução Em sistemas distribuídos, operações de I/O como requisições HTTP, consultas a bancos de dados e streaming de mensagens são fundamentais para fluxos de trabalho. Embora o padrão async/await do .NET gerencie essas operações com eficiência, integrar manipuladores assíncronos ao Brighter requer configuração explícita. Este artigo explora como habilitar manipuladores assíncronos no Brighter e explica a arquitetura por trás de seu design, baseada nos padrões Reactor e Proactor. Manipuladores Assíncronos sem Configuração Ao usar SqsSubscription ou KafkaSubscription do Brighter, tentar usar RequestHandlerAsync sem configuração adequada resulta em erro: Paramore.Brighter.ConfigurationException: Error when building pipeline, see inner Exception for details ---> System.InvalidCastException: Unable to cast object of type 'GreetingHandler' to type 'Paramore.Brighter.IHandleRequests'. Isso ocorre porque o Brighter usa o padrão Reactor(I/O síncrono) por padrão e não consegue inferir se seu manipulador requer o padrão Proactor (I/O assíncrono). Solução: Habilitar Processamento Assíncrono Para resolver, defina isAsync: true na configuração da inscrição: .AddServiceActivator(opt => { opt.Subscriptions = [ new SqsSubscription( new SubscriptionName("greeting-subscription"), new ChannelName("greeting-queue"), new RoutingKey("greeting.topic".ToValidSNSTopicName()), bufferSize: 2, isAsync: true) // Habilita processamento assíncrono ]; opt.ChannelFactory = new ChannelFactory(connection); }) Isso permite usar RequestHandlerAsync para operações não bloqueantes: public class GreetingHandler(ILogger logger) : RequestHandlerAsync { public override async Task HandleAsync(Greeting command) { logger.LogInformation("Processando {Name}", command.Name); await Task.Delay(1_000); // Simula I/O assíncrono (ex: chamada HTTP) logger.LogInformation("Olá, {Name}", command.Name); return await base.HandleAsync(command); } } Message pump(A Bomba de Mensagens): Núcleo do Processamento do Brighter O Brighter usa um message pump single-threaded para garantir ordenação e evitar condições de corrida. O processo segue três etapas: GetMessage: Lê mensagens da fila. Translate Message: Desserializa para um tipo .NET. Dispatch Message: Roteia para o manipulador adequado. Por Que usar Single-Threaded pumps? Abordagens alternativas, como BlockingCollection ou thread-per-message, introduzem problemas críticos: Abordagem Problemas Multithread pump Risco de reordenar mensagens, violando garantias FIFO. Thread Pool Esgota threads sob carga, causando gargalos com semáforos. A solução do Brighter é uma single-threaded pumps, garantindo processamento em ordem sem contenção de threads. Padrões Reactor vs. Proactor A message pump do Brighter opera em dois modos, determinados pela flag isAsync: Reactor (isAsync: false) I/O Síncrono: Processa mensagens sequencialmente em uma única thread. Desempenho Previsível: Evita overhead de thread pool e trocas de contexto. Limitação: Bloqueia em I/O, reduzindo throughput para operações longas. Proactor (isAsync: true) I/O Assíncrono: Usa async/await para evitar bloqueios, aumentando throughput. Integração com Thread Pool: Aproveita o SynchronizationContext do .NET para preservar a ordem. Trade-off: Overhead leve devido ao gerenciamento de estado assíncrono. Por Que o Brighter Exige isAsync? O Brighter não detecta automaticamente se seu manipulador usa I/O síncrono ou assíncrono porque: Alocação de Recursos: A escolha entre Reactor/Proactor impacta threads e memória. Prevenção de Deadlocks: Manipuladores assíncronos exigem pipelines dedicados. Garantias de Desempenho: Configuração explícita otimiza throughput e latência. Conclusão A flag isAsync do Brighter é uma escolha de design que equilibra desempenho e escalabilidade: Evite Erros em Runtime: Declare manipuladores assíncronos explicitamente. Preserve a Ordem: A single-threaded pumps garante processamento sequencial, mesmo com I/O assíncrono. Alinhando-se a padrões estabelecidos, o Brighter oferece mensageria eficiente e thread-safe para sistemas distribuídos. Referências Brighter ADR: Message Pump Single-Threaded Brighter ADR: Suporte a Pipelines Assíncronos GitHub full code

May 2, 2025 - 09:15
 0
Brighter: Handler Assíncronos

Introdução

Em sistemas distribuídos, operações de I/O como requisições HTTP, consultas a bancos de dados e streaming de mensagens são fundamentais para fluxos de trabalho. Embora o padrão async/await do .NET gerencie essas operações com eficiência, integrar manipuladores assíncronos ao Brighter requer configuração explícita. Este artigo explora como habilitar manipuladores assíncronos no Brighter e explica a arquitetura por trás de seu design, baseada nos padrões Reactor e Proactor.

Manipuladores Assíncronos sem Configuração

Ao usar SqsSubscription ou KafkaSubscription do Brighter, tentar usar RequestHandlerAsync sem configuração adequada resulta em erro:

Paramore.Brighter.ConfigurationException: Error when building pipeline, see inner Exception for details
 ---> System.InvalidCastException: Unable to cast object of type 'GreetingHandler' to type 'Paramore.Brighter.IHandleRequests'.

Isso ocorre porque o Brighter usa o padrão Reactor(I/O síncrono) por padrão e não consegue inferir se seu manipulador requer o padrão Proactor (I/O assíncrono).

Solução: Habilitar Processamento Assíncrono

Para resolver, defina isAsync: true na configuração da inscrição:

.AddServiceActivator(opt =>
{
    opt.Subscriptions = [
        new SqsSubscription<Greeting>(
            new SubscriptionName("greeting-subscription"),
            new ChannelName("greeting-queue"),
            new RoutingKey("greeting.topic".ToValidSNSTopicName()),
            bufferSize: 2,
            isAsync: true) // Habilita processamento assíncrono
    ];
    opt.ChannelFactory = new ChannelFactory(connection);
})

Isso permite usar RequestHandlerAsync para operações não bloqueantes:

public class GreetingHandler(ILogger<GreetingHandler> logger) : RequestHandlerAsync<Greeting>
{
    public override async Task<Greeting> HandleAsync(Greeting command)
    {
        logger.LogInformation("Processando {Name}", command.Name);
        await Task.Delay(1_000);  // Simula I/O assíncrono (ex: chamada HTTP)
        logger.LogInformation("Olá, {Name}", command.Name);
        return await base.HandleAsync(command);
    }
}

Message pump(A Bomba de Mensagens): Núcleo do Processamento do Brighter

O Brighter usa um message pump single-threaded para garantir ordenação e evitar condições de corrida. O processo segue três etapas:

  1. GetMessage: Lê mensagens da fila.
  2. Translate Message: Desserializa para um tipo .NET.
  3. Dispatch Message: Roteia para o manipulador adequado.

Por Que usar Single-Threaded pumps?

Abordagens alternativas, como BlockingCollection ou thread-per-message, introduzem problemas críticos:

Abordagem Problemas
Multithread pump Risco de reordenar mensagens, violando garantias FIFO.
Thread Pool Esgota threads sob carga, causando gargalos com semáforos.

A solução do Brighter é uma single-threaded pumps, garantindo processamento em ordem sem contenção de threads.

Padrões Reactor vs. Proactor

A message pump do Brighter opera em dois modos, determinados pela flag isAsync:

Reactor (isAsync: false)

  • I/O Síncrono: Processa mensagens sequencialmente em uma única thread.
  • Desempenho Previsível: Evita overhead de thread pool e trocas de contexto.
  • Limitação: Bloqueia em I/O, reduzindo throughput para operações longas.

Proactor (isAsync: true)

  • I/O Assíncrono: Usa async/await para evitar bloqueios, aumentando throughput.
  • Integração com Thread Pool: Aproveita o SynchronizationContext do .NET para preservar a ordem.
  • Trade-off: Overhead leve devido ao gerenciamento de estado assíncrono.

Por Que o Brighter Exige isAsync?

O Brighter não detecta automaticamente se seu manipulador usa I/O síncrono ou assíncrono porque:

  1. Alocação de Recursos: A escolha entre Reactor/Proactor impacta threads e memória.
  2. Prevenção de Deadlocks: Manipuladores assíncronos exigem pipelines dedicados.
  3. Garantias de Desempenho: Configuração explícita otimiza throughput e latência.

Conclusão

A flag isAsync do Brighter é uma escolha de design que equilibra desempenho e escalabilidade:

  • Evite Erros em Runtime: Declare manipuladores assíncronos explicitamente.
  • Preserve a Ordem: A single-threaded pumps garante processamento sequencial, mesmo com I/O assíncrono.

Alinhando-se a padrões estabelecidos, o Brighter oferece mensageria eficiente e thread-safe para sistemas distribuídos.

Referências