Arquitetura Orientada a Eventos - Design de Sistemas Fracamente Acoplados

16 min leitura | 2025.12.12

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