Padrões de arquitetura event-driven em produção: dead letters, sagas e quando fazer event sourcing
Arquiteturas event-driven prometem baixo acoplamento e escalabilidade. Em produção, elas entregam dead letter queues, orquestração de sagas e a difícil decisão de quando event sourcing vale a complexidade.
Resumo executivo
Arquiteturas event-driven prometem baixo acoplamento e escalabilidade. Em produção, elas entregam dead letter queues, orquestração de sagas e a difícil decisão de quando event sourcing vale a complexidade.
Ultima atualizacao: 19/03/2026
Resumo executivo
A transição de sistemas síncronos request/response para arquiteturas assíncronas event-driven resolve problemas reais: serviços são fracamente acoplados, sistemas podem escalar independentemente, e processos de negócio podem executar através de horas ou dias ao invés de dentro de um único timeout de requisição HTTP.
Mas sistemas event-driven de produção introduzem novos modos de falha que não existem em sistemas síncronos. O que acontece quando um consumidor de mensagens cai no meio do processamento? Como compensar um pagamento que foi bem-sucedido quando a reserva subsequente de inventário falhou? Quando a promessa de trilhas de auditoria perfeitas do event sourcing vale a complexidade de implementação?
Este post cobre os padrões que separam sistemas de eventos de prova de conceito de arquiteturas event-driven com grau de produção.
Dead letter queues: o padrão que você precisa antes de ir para produção
Uma dead letter queue (DLQ) é um destino para mensagens que não podem ser processadas com sucesso após um número configurado de tentativas. É o padrão mais subestimado em sistemas event-driven, e o primeiro que você vai desejar ter quando chegar em produção.
Padrões de design de DLQ
DLQ por consumidor vs DLQ compartilhada:
Para a maioria dos sistemas, crie uma DLQ separada por consumidor (ou por grupo de consumidores). Isso permite investigação direcionada e reprocessamento sem mensagens não relacionadas criarem ruído. Uma DLQ compartilhada é aceitável apenas para equipes muito pequenas onde simplicidade operacional supera benefícios de isolamento.
Enriquecimento de mensagem antes da DLQ:
Ao mover uma mensagem para a DLQ, enriqueça-a com metadados operacionais antes que o payload original seja perdido:
json{
"mensagemOriginal": { /* payload original */ },
"metadadosDeFalha": {
"consumidor": "order-fulfillment-service",
"motivoDaFalha": "INVENTORY_SYSTEM_TIMEOUT",
"tentativas": 3,
"primeiraFalhaAs": "2026-03-19T10:23:45Z",
"ultimaFalhaAs": "2026-03-19T10:26:12Z",
"duracaoTentativaMs": [1250, 1800, 2100]
}
}Esses metadados são valiosos ao investigar problemas de produção e decidir se deve reprocessar, modificar ou descartar permanentemente mensagens.
Estratégias de retry: backoff exponencial com jitter
Quando o processamento de uma mensagem falha, retry imediato frequentemente cria um problema de thundering herd que piora a questão subjacente. Backoff exponencial com jitter é a abordagem padrão:
- Delay inicial: 1 segundo
- Base exponencial: 2 (delay dobra a cada retry)
- Delay máximo: 5 minutos
- Jitter: variação aleatória de ±25% para prevenir sincronização
Para falhas transitórias (timeouts de rede, indisponibilidade temporária de serviço), essa abordagem permite que o sistema se recupere sem sobrecarregar dependências. Para falhas permanentes (schema de mensagem inválido, dados ausentes), a mensagem rapidamente chega à DLQ ao invés de consumir capacidade de retry indefinidamente.
Operações de DLQ: visibilidade e reprocessamento
Uma DLQ é operacionalmente útil apenas quando você tem ferramental para inspecionar e reprocessar mensagens. Requisitos mínimos:
- Busca e filtro: Encontrar mensagens por tipo de erro, tópico original ou intervalo de tempo
- Inspeção de mensagem: Visualizar o payload original e metadados de falha
- Mecanismo de replay: Reprocessar mensagens individualmente ou em lote
- Editar antes do replay: Corrigir mensagens malformadas sem redeployar código
Opções de ferramental:
- Kafka: Ferramentas de UI como Kafka Explorer, ou consumidor customizado com APIs admin
- RabbitMQ: Dead letter exchange com plugins shovel para movimento de mensagens
- AWS SQS: Suporte nativo a DLQ com capacidade de redrive
- Cloud Pub/Sub: Dead lettering nativo com extensão de prazo de acknowledgment
Padrão saga: gerenciando transações distribuídas sem two-phase commit
Em um sistema síncrono, você pode envolver operações multi-serviço em uma transação de banco de dados usando two-phase commit. Em sistemas event-driven, isso não é prático nem desejável. O padrão saga coordena um processo de negócio através de múltiplos serviços via uma sequência de transações locais, cada uma com uma transação compensatória para rollback.
Coreografia vs orquestração
Coreografia: Cada serviço emite eventos e reage a eventos de outros serviços. Não há coordenador central; a saga emerge da interação de serviços.
Melhor para: Workflows simples com 2-3 participantes, fronteiras de equipe estáveis onde cada serviço é de propriedade de uma equipe diferente.
Orquestração: Um serviço orquestrador de saga central mantém o estado da saga e envia comandos para serviços participantes. Participantes respondem com eventos que o orquestrador consome.
Melhor para: Workflows complexos com 4+ participantes, workflows que mudam frequentemente, workflows que requerem visibilidade do estado atual.
Implementando sagas orquestradas
Sagas orquestradas requerem gerenciamento de estado persistente. Cada instância de saga deve ser armazenada em um banco de dados com:
- ID da saga
- Estado atual (qual passo foi completado)
- Dados de payload (identificadores de negócio, resultados intermediários)
- Histórico de passos completados (para auditoria e compensação)
Exemplo de máquina de estado: Cumprimento de pedido
[PENDENTE] → [PAGAMENTO_INICIADO] → [PAGAMENTO_CONFIRMADO] → [INVENTARIO_RESERVADO] → [ENVIO_AGENDADO] → [COMPLETADO]
↓ ↓
[PAGAMENTO_FALHOU] [INVENTARIO_FALHOU]
↓ ↓
[COMPENSADO] ← [COMPENSADO]
↓
[FALHOU]Cada transição de estado é disparada por um evento de um serviço participante. O orquestrador inicia compensação enviando comandos compensatórios para todos participantes completados em ordem reversa.
Design de compensação: nem todas operações podem ser desfeitas
Transações compensatórias nem sempre são inversos simples da transação original. Considere:
- Pagamento: Captura → Reembolso (direto)
- Reserva de inventário: Reservar → Liberar (direto)
- Envio: Agendar envio → Não pode "desagendar" um envio uma vez despachado (compensação: processar devolução, emitir reembolso)
- Notificação por email: Enviar email de boas-vindas → Não pode "desenviar" um email (compensação: enviar email de correção, registrar a questão)
Designe sua saga com o entendimento de que algumas operações são compensáveis, algumas não, e planeje processos de negócio de acordo.
Event sourcing: quando a complexidade vale a pena
Event sourcing armazena todas mudanças ao estado da aplicação como uma sequência de eventos ao invés de apenas o estado atual. Para reconstruir o estado atual, você repete todos eventos desde o início dos tempos.
Quando event sourcing faz sentido
Use event sourcing quando:
- Auditoria é requisito de primeira classe: Sistemas financeiros, aplicações de saúde e indústrias regulamentadas onde o histórico completo de mudanças de estado é um requisito regulatório
- Lógica de negócio complexa: Sistemas onde o estado atual é insuficiente para entender por que o sistema está em seu estado atual (underwriting de seguro, decisão de crédito)
- Queries temporais: Sistemas que precisam responder "qual era o estado no tempo T?" (sistemas de assinatura, cobrança)
- Replay de evento é valioso: Sistemas onde recalcular estado de eventos é operacionalmente útil (corrigir bugs em lógica de negócio, backfill de dados derivados)
Evite event sourcing quando:
- Seu domínio é CRUD simples: A maioria de aplicações web tradicionais não se beneficia de event sourcing
- Sua equipe não tem experiência com event sourcing: A curva de aprendizado é íngreme; o primeiro sistema event-sourced levará mais tempo que o esperado
- Você não tem recursos para ferramental: Event sourcing requer ferramental para gerenciamento de snapshot, queries de event store e infraestrutura de replay
Padrões de implementação de event sourcing
Schema de event store:
Cada evento requer:
- ID do evento (UUID)
- ID do agregado (a entidade a que o evento pertence)
- Tipo de evento (ex:
OrderPlaced,PaymentCaptured) - Dados do evento (payload específico de negócio)
- Metadados (timestamp, ID de causação, ID de correlação, ID de usuário)
- Número de versão (para concorrência otimista)
Estratégia de snapshot:
Reproduzir milhões de eventos para computar estado atual é proibitivamente caro. Implemente snapshots:
- Frequência: A cada N eventos (ex: a cada 100 eventos) ou baseado em tempo (a cada 24 horas)
- Armazenamento: Mesmo event store ou store de snapshot separado
- Formato de snapshot: Estado completo do agregado no ponto do snapshot
- Padrão de query: Carregar snapshot mais recente, depois reproduzir eventos desde snapshot
Versionamento de evento:
Schemas de evento evoluem. Quando um tipo de evento muda, você precisa lidar com eventos antigos e novos:
- Upcast: Ler eventos antigos e transformar para novo schema no replay
- Tipos de evento versionados:
OrderPlacedV1,OrderPlacedV2 - Modelos de leitura separados: Projetar eventos em múltiplos modelos de leitura otimizados para queries
Preocupações operacionais de event sourcing
Event sourcing introduz complexidade operacional além de persistência de estado tradicional:
- Performance de event store: Todas leituras requerem replay de evento; otimize com snapshots e projeções de modelo de leitura
- Migração de schema: Mudar schemas de evento requer lidar com eventos históricos com schemas antigos
- Deleções de evento: Regulamentação de "direito ao esquecimento" requer tratamento especial em logs de evento
- Complexidade de debugging: Entender estado atual requer entender histórico de evento, não apenas linhas de banco de dados
Seleção de message broker: Kafka vs RabbitMQ vs cloud-native
A escolha de message broker molda seus padrões de arquitetura event-driven.
Kafka: streams, não filas
Kafka é um sistema de mensagens baseado em log otimizado para streaming de fluxos de evento de alta vazão e duráveis. Não é uma fila de mensagens tradicional.
Quando escolher Kafka:
- Streaming de evento de alta vazão (milhões de eventos por segundo)
- Múltiplos consumidores independentes lendo os mesmos eventos (stream processing, analytics)
- Requisitos de event sourcing ou replay de evento
- Retenção de evento longa (dias a semanas)
Considerações operacionais do Kafka:
- Gerenciamento de grupo de consumidores para escalabilidade horizontal
- Estratégia de sizing de partição (muito poucas partições limitam paralelismo; muitas aumentam overhead)
- Gerenciamento de broker e ZooKeeper/KRaft
- Compaction de tópico para semântica de estado mais recente
RabbitMQ: roteamento flexível, menor complexidade
RabbitMQ é um message broker tradicional com capacidades de roteamento sofisticadas através de exchanges e bindings.
Quando escolher RabbitMQ:
- Workflows requerendo roteamento complexo (roteamento baseado em conteúdo, multicast, request-reply)
- Menor complexidade operacional que Kafka
- Workloads que não requerem escala ou garantias de durabilidade do Kafka
- Equipes com expertise RabbitMQ existente
Considerações operacionais do RabbitMQ:
- Durabilidade e espelhamento de fila para alta disponibilidade
- Gerenciamento de conexão e canal
- Alarmes de memória e disco
- Ecossistema de plugins (Shovel para movimento de mensagem, Federation para multi-região)
Opções cloud-native: infraestrutura gerenciada
AWS SQS/SNS/Kinesis:
- SQS: Serviço de fila simples, pricing por mensagem, sem gerenciamento de infraestrutura
- SNS: Messaging pub/sub, fanout para múltiplos assinantes
- Kinesis: Streaming em tempo real, integra com Lambda e serviços de analytics
Google Cloud Pub/Sub:
- Entrega pelo menos uma vez, integra com ecossistema GCP
- Dead lettering nativo e extensão de prazo de acknowledgment
Azure Service Bus:
- Recursos de mensagens empresariais (sessões, entrega agendada, adiamento de mensagem)
- Diversidade de protocolo (AMQP, MQTT, HTTP)
Opções cloud-native reduzem overhead operacional mas introduzem vendor lock-in e custo potencial em escala.
Testando sistemas event-driven: além de testes unitários
Sistemas event-driven requerem testes além de testes unitários tradicionais:
- Testes de contrato de consumidor: Verificar que consumidores podem lidar com todas variantes de mensagem que se inscrevem
- Testes de contrato de produtor: Verificar que produtores emitem mensagens que combinam com schemas esperados
- Testes de integração com broker embutido: Testar produtor e consumidor junto com um message broker real (Testcontainers para Kafka/RabbitMQ)
- Testes de caos: Simular indisponibilidade de broker, crashes de consumidor e partições de rede para verificar resiliência
- Testes de saga: Verificar que orquestradores de saga compensam corretamente falhas em cada passo
Prompts de decisão para equipes de arquitetura
- Quando uma mensagem falha no processamento, sua equipe de operações pode inspecionar a falha, entender a causa raiz e reproduzir a mensagem sem implantar novo código?
- Para seus workflows multi-serviço mais críticos, a lógica de coordenação (saga) é visível e debugável, ou está escondida em coreografia implícita?
- Você desenhou explicitamente transações compensatórias para cada passo em suas transações distribuídas, ou está assumindo sucesso?
- Se você está fazendo event sourcing, tem ferramental para gerenciamento de snapshot e replay de evento, ou seu primeiro replay de evento será uma emergência manual de produção?
Projetando uma arquitetura event-driven de produção com tratamento de falhas e resiliência apropriados? Fale com a Imperialis sobre orquestração de saga, avaliação de event sourcing e seleção de message broker.
Fontes
- Distributed sagas — Microservices.io patterns, 2026 — acessado em março 2026
- Event sourcing explained — Martin Fowler, 2026 — acessado em março 2026
- Dead letter queues — AWS Architecture Center, 2026 — acessado em março 2026
- Comparação Kafka vs RabbitMQ — Confluent, 2026 — acessado em março 2026