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

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:
- 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.