Event-driven architecture é linda no papel. Desacoplada, escalável e reativa.
Na prática? Nem sempre. Porque o problema não é publicar eventos. É lidar com o que acontece depois.
O fluxo que parece simples
Você tem um fluxo clássico: Pedido criado, pagamento processado e notificação enviada.
Em arquitetura orientada a eventos, isso vira algo assim:
await eventBus.publish('order_created', order);
E aí:
Payment-service consome, notification-service consome e analytics consome
Perfeito.
Até dar problema.
O primeiro choque: você perdeu o controle do fluxo
No monólito, o fluxo é explícito. Em event-driven, ele é implícito.
Você dispara um evento. E… torce.
Não existe mais garantia de ordem clara. Não existe mais caminho único.
E quando algo quebra… Você não sabe exatamente onde.
Debugging deixa de ser técnico
Vira investigativo. Você começa com um bug: “Pedido não foi cobrado”
Agora precisa descobrir: Evento foi publicado? Foi consumido? Falhou? Reprocessou? Duplicou?
Exemplo real:
consumer.run({
eachMessage: async ({ message }) => {
const order = JSON.parse(message.value);
await processPayment(order);
}
});
Parece simples. Mas se processPayment falhar? Você não sabe se o evento vai ser reprocessado, se vai ser perdido ou vai gerar efeito duplicado.
Agora você não está debugando código. Você está reconstruindo uma linha do tempo.
Inconsistência de dados deixa de ser exceção
Vira padrão. Exemplo clássico:
// order-service
await db.insert(order);
await eventBus.publish('order_created', order);
E no outro lado:
// payment-service
consumer.run({
eachMessage: async ({ message }) => {
const order = JSON.parse(message.value);
await charge(order);
}
});
Agora imagina:
Evento chega antes da base estar consistente, serviço lê dado incompleto ou falha no meio do processamento
Resultado: Estado inconsistente. E isso não é bug raro. É comportamento esperado.
Idempotência: o retrabalho obrigatório
Se você usa eventos, você precisa aceitar uma coisa: Eventos podem ser processados mais de uma vez.
Então você precisa fazer isso:
async function processPayment(order) {
const alreadyProcessed = await db.findPayment(order.id);
if (alreadyProcessed) return;
await paymentGateway.charge(order);
}
Funciona. Mas agora você adicionou mais query, mais lógica e mais pontos de falha. Tudo isso para lidar com duplicidade. E isso vai se repetir em vários serviços.
Ordem de eventos: a armadilha silenciosa
Você assume que eventos chegam na ordem certa. Mas nem sempre chegam.
Exemplo:
order_created
order_cancelled
Agora imagina chegar assim:
order_cancelled
order_created
Seu sistema pode: cobrar um pedido cancelado ou até reativar algo que não deveria
E aí? Você precisa de controle de versão.
if (event.version < currentVersion) return;
Mais complexidade. Mais estado. Mais chance de erro.
Latência invisível
Event-driven adiciona latência. Você publica. E espera o processamento. Exemplo:
await createOrder(order);
// depende de evento para continuar fluxo
O usuário não vê imediatamente. Ou vê comportamento inconsistente.
E aí começa: “Mas no meu sistema funciona…”
Até não funcionar.
O efeito dominó
Um serviço falha. Fila acumula. Outro serviço atrasa. E de repente: Sistema inteiro degradado.
Você não tem mais falha isolada. Tem falha distribuída.
Ou seja, observabilidade não é opcional. Sem isso, esquece.
Você precisa de: Correlation ID, Tracing distribuído e Logs centralizados
Exemplo:
const event = {
id: uuid(),
correlationId,
type: 'order_created',
payload: order
};
Sem isso… Você está cego.
O custo que ninguém considera
Event-driven não é só arquitetura. É operação contínua.
Você precisa manter:
- Broker
- Consumers
- Monitoramento
- Retries
- Dead letter queues
E cada item desses pode falhar.
Quando faz sentido de verdade
Event-driven funciona bem quando:
- Você tem alto volume de eventos
- Múltiplos consumidores independentes
- Processamento assíncrono real
- Necessidade de desacoplamento forte
Tipo: Streaming, Analytics e Sistemas altamente distribuídos
Fora disso… Pode ser exagero.
O ponto que ninguém fala
Event-driven não simplifica. Ele troca tipo de complexidade. Sai o fluxo explícito e entra o comportamento emergente. E comportamento emergente é mais difícil de controlar.
Ou seja, Event-driven architecture funciona. Mas cobra caro em debugging, em consistência e em complexidade.
E se você não precisa disso ainda… Provavelmente está pagando esse custo sem necessidade. Porque no fim…
Publicar evento é fácil. Difícil é viver com ele em produção.




