Why Event-Driven Architecture?
EDA enables loose coupling, temporal decoupling, and audit trails by default. But it also introduces complexity around ordering, consistency, and error handling.
Core Patterns
1. Event Notification
The simplest pattern: emit an event when something happens, let other services react.
await eventBus.emit("order.created", {
orderId: order.id,
customerId: order.customerId,
items: order.items,
total: order.total
});2. Event Sourcing
Store every state change as an immutable event. The current state is derived by replaying events.
const events = [
{ type: "OrderCreated", data: { items: [...] }, timestamp: "2025-01-15T10:00:00Z" },
{ type: "PaymentReceived", data: { amount: 100 }, timestamp: "2025-01-15T10:05:00Z" },
{ type: "OrderShipped", data: { carrier: "FedEx", tracking: "123" }, timestamp: "2025-01-16T09:00:00Z" }
];3. CQRS (Command Query Responsibility Segregation)
Separate read and write models for different performance needs. Write model optimizes for consistency, read model optimizes for query performance.
Message Broker Selection
| Broker | Best For | Trade-offs |
|---|---|---|
| RabbitMQ | Complex routing, reliability | Lower throughput than Kafka |
| Kafka | High throughput, event sourcing | Higher operational complexity |
| SQS/SNS | Simple queue/pub-sub | AWS lock-in |
Handling Failures
- Dead Letter Queues for messages that can't be processed
- Idempotency keys for duplicate processing
- Circuit breakers for downstream service failures
- Saga pattern for distributed transactions