O Que e Arquitetura Orientada a Eventos
Arquitetura Orientada a Eventos (EDA: Event-Driven Architecture) e um padrao de design onde a comunicacao entre sistemas e feita atraves de eventos (notificacoes de ocorrencias). Ela reduz dependencias entre componentes e permite construir sistemas escalaveis e flexiveis.
O que e um evento: E uma mensagem que representa uma mudanca de estado significativa que ocorreu no sistema. Exemplos de eventos incluem “Usuario foi registrado”, “Pedido foi concluido”, “Estoque foi reduzido”.
Diferenca da Abordagem Tradicional Orientada a Requisicoes
Orientada a Requisicoes (Sincrona)
flowchart LR
Order["Servico de Pedidos"] --> Stock["Servico de Estoque"] --> Payment["Servico de Pagamento"] --> Notify["Servico de Notificacao"]
Note["Aguarda resposta de cada servico"]
- Servicos fortemente acoplados
- Falha em um servico afeta todo o sistema
- Tempo de processamento e a soma de todos os servicos
Orientada a Eventos (Assincrona)
flowchart TB
Order["Servico de Pedidos"] --> Event["Evento de Pedido Concluido"]
Event --> Stock["Servico de Estoque<br/>(processa independentemente)"]
Event --> Payment["Servico de Pagamento<br/>(processa independentemente)"]
Event --> Notify["Servico de Notificacao<br/>(processa independentemente)"]
- Servicos fracamente acoplados
- Falhas sao localizadas
- Processamento paralelo e possivel
Tipos de Eventos
Eventos de Dominio
Representam ocorrencias que aconteceram no dominio de negocios.
// Exemplo de evento de dominio
{
"eventType": "OrderPlaced",
"eventId": "evt_123456",
"timestamp": "2024-01-15T10:30:00Z",
"payload": {
"orderId": "ord_789",
"customerId": "cust_456",
"items": [...],
"totalAmount": 5000
}
}
Eventos de Integracao
Eventos compartilhados entre diferentes servicos.
Eventos de Notificacao
Eventos que apenas notificam mudancas de estado, sem conter dados detalhados.
// Evento de notificacao (Fat vs Thin)
// Thin Event - Detalhes devem ser buscados separadamente
{ "eventType": "UserUpdated", "userId": "123" }
// Fat Event - Contem todas as informacoes necessarias
{ "eventType": "UserUpdated", "userId": "123", "name": "Alice", "email": "..." }
Event Sourcing
Padrao que armazena o estado como um historico de eventos.
CRUD Tradicional
flowchart TB
subgraph CRUD["CRUD Tradicional - Armazena apenas o estado atual"]
Orders["orders<br/>id: 1, status: 'shipped'"]
end
Event Sourcing
flowchart TB
subgraph Events["Armazena todos os eventos"]
E1["1. OrderCreated (2024-01-01)"]
E2["2. PaymentReceived (2024-01-02)"]
E3["3. OrderShipped (2024-01-03)"]
end
Events -->|Replay| State["Estado atual: status = 'shipped'"]
Vantagens
- Trilha de auditoria completa: Todas as mudancas podem ser rastreadas
- Viagem no tempo: Pode reconstruir o estado em qualquer ponto no tempo
- Replay de eventos: Pode reconstruir o estado apos correcao de bugs
Desvantagens
- Aumenta a complexidade
- Evolucao do esquema de eventos e um desafio
- Requer otimizacao para performance de leitura
CQRS (Segregacao de Responsabilidade de Comando e Consulta)
Padrao que separa os modelos de leitura (Query) e escrita (Command).
flowchart TB
Command["Command<br/>(Modelo de Escrita)"]
Command -->|Publica evento| EventStore["Event Store"]
EventStore -->|Projecao| Query["Query<br/>(Modelo de Leitura)"]
Modelo de Escrita
// Command handler
async function handlePlaceOrder(command) {
const order = new Order(command.orderId);
order.addItems(command.items);
order.place();
await eventStore.save(order.getUncommittedEvents());
}
Modelo de Leitura
// View otimizada para leitura
const orderSummary = {
orderId: "123",
customerName: "Alice", // Informacoes do cliente ja unidas
itemCount: 3,
totalAmount: 5000,
status: "shipped"
};
Padroes de Implementacao
Padrao Saga
Realiza transacoes que abrangem multiplos servicos atraves de uma cadeia de eventos.
1. Criar pedido → OrderCreated
2. Reservar estoque → InventoryReserved (ou InventoryReservationFailed em caso de falha)
3. Processar pagamento → PaymentProcessed (ou PaymentFailed em caso de falha)
4. Confirmar pedido → OrderConfirmed
Em caso de falha, transacao compensatoria:
PaymentFailed → Liberar estoque (compensacao) → Cancelar pedido
Padrao Outbox
Padrao para garantir a atualizacao do banco de dados e a publicacao de eventos.
1. Dentro de uma transacao:
- Atualizar dados de negocios
- Inserir evento na tabela outbox
2. Em processo separado:
- Fazer polling da tabela outbox
- Publicar eventos na fila de mensagens
- Marcar como publicado
Desafios a Considerar
Consistencia Eventual
Servico de Pedidos: status do pedido = "concluido"
Servico de Estoque: evento ainda nao processado → periodo de inconsistencia existe
↓ Apos processamento do evento
Servico de Estoque: estoque reduzido → consistencia restaurada
Ordem dos Eventos
Ordem correta:
1. OrderCreated
2. OrderUpdated
3. OrderShipped
Se a ordem for alterada:
1. OrderShipped (?)
2. OrderCreated
→ Estado pode ser corrompido
Idempotencia
Projete para que o mesmo evento sendo entregue multiplas vezes nao altere o resultado.
async function handleInventoryReserved(event) {
// Verificar duplicatas com chave de idempotencia
const processed = await db.processedEvents.findById(event.eventId);
if (processed) return;
await db.inventory.reserve(event.payload);
await db.processedEvents.insert({ eventId: event.eventId });
}
Resumo
Arquitetura Orientada a Eventos e um padrao poderoso para projetar sistemas complexos de forma fracamente acoplada e flexivel. Quando combinada com Event Sourcing e CQRS, pode melhorar a auditabilidade e escalabilidade. No entanto, e necessario lidar com desafios especificos de sistemas distribuidos, como consistencia eventual e ordenacao de eventos.
← Voltar para a lista