Pular para o conteúdo principal

Domain Event

Descrição​

Um evento de domínio (Domain Event), conceito vindo do Domain-Driven Design, é um fato relevante para o negócio que ocorreu no domínio, como PedidoCriado ou CreditoReservado. No padrão, a lógica de negócio de um serviço é estruturada em agregados (aggregates), e cada agregado emite um evento de domínio sempre que é criado ou alterado. O serviço publica esses eventos para que outros serviços possam consumi-los.

Os eventos são nomeados no passado, imutáveis e carregam os dados necessários para que os consumidores reajam sem precisar consultar o emissor. Eles são o insumo para atualizar visões CQRS, manter réplicas locais e conduzir sagas coreografadas.

No DDD, o Domain Event é antes de tudo um fato do domínio: algo que aconteceu e que os especialistas do negócio consideram relevante, nomeado com a linguagem ubíqua. Ele é produzido pelo Aggregate e pode ser tratado dentro do próprio contexto, para propagar consistência eventual entre agregados, ou publicado para outros contextos, como contrato de integração.

O padrão em si define o que publicar; a publicação confiável (atômica com a atualização do banco) é tratada por padrões como Transactional Outbox ou Event Sourcing.

Problemas que resolve​

  • Como um serviço publica um evento quando atualiza seus dados.
  • Como permitir que outros serviços reajam a mudanças sem acoplamento direto ao emissor.
  • Como alimentar visões CQRS, réplicas e passos de sagas coreografadas com fatos confiáveis do domínio.

Quando usar​

  • Quando outros serviços precisam reagir a mudanças de estado, como em sagas por coreografia.
  • Quando é preciso manter visões ou réplicas derivadas atualizadas.
  • Quando a lógica de negócio já é modelada com agregados.

Quando evitar​

  • Quando nenhum outro componente precisa ser notificado das mudanças.
  • Quando não há infraestrutura de mensageria nem como garantir a publicação atômica com a gravação no banco.
  • Quando a granularidade dos eventos tende a expor detalhes internos do modelo, gerando acoplamento.

Trade-offs​

GanhoCusto / Risco
Baixo acoplamento entre emissor e consumidoresOs eventos viram contrato público que precisa ser versionado
Base para CQRS, réplicas e sagas coreografadasConsistência eventual entre emissor e consumidores
Linguagem alinhada ao domínio de negócioPublicação confiável exige Transactional Outbox ou Event Sourcing
Novos consumidores podem ser adicionados sem alterar o emissorFluxos baseados em eventos são mais difíceis de rastrear e depurar
  • Atomicidade: atualizar o banco e publicar o evento deve ser atômico; do contrário, dados e eventos divergem.
  • Duplicidade e ordem: a entrega costuma ser at least once, exigindo consumidores idempotentes e atenção à ordenação por agregado.
  • Conteúdo: eventos muito enxutos forçam consultas de volta ao emissor; muito gordos vazam detalhes internos.

Diagrama​

O agregado emite o evento, o serviço o publica e diferentes consumidores reagem a ele, cada um à sua maneira.

Exemplo​

Um pedido registra o evento OrderCreated ao ser criado; após persistir o agregado, o serviço publica os eventos acumulados.

public record OrderCreated(String orderId, String customerId, Instant occurredAt) {}

public class Order {
private final String id;
private final String customerId;
private final List<Object> events = new ArrayList<>();

public Order(String id, String customerId) {
this.id = id;
this.customerId = customerId;
events.add(new OrderCreated(id, customerId, Instant.now()));
}

public List<Object> pullEvents() {
List<Object> copy = List.copyOf(events);
events.clear();
return copy;
}
}

public class OrderService {
@Transactional
public void create(String id, String customerId) {
Order order = new Order(id, customerId);
orders.save(order);
order.pullEvents().forEach(publisher::publish); // ex.: via Transactional Outbox
}
}

Padrões relacionados​

  • Aggregate — o agregado é a fonte natural dos eventos de domínio.
  • Saga — sagas coreografadas dependem de eventos de domínio.
  • CQRS — visões de leitura são atualizadas por esses eventos.
  • Command-side Replica — réplicas locais são mantidas pelos eventos.
  • Event Sourcing — pode ser usado para gerar e publicar eventos de domínio.
  • Transactional Outbox — publica os eventos de forma atômica com a transação do banco.
  • Messaging — estilo de comunicação usado para distribuir os eventos.
  • Publisher-Subscriber — modelo de distribuição dos eventos a múltiplos consumidores.

Referência​