What Is Event-Driven Architecture? A Complete Guide
Are your services tightly coupled? Does a change in one service break others? Event-Driven Architecture decouples services through events, enabling scalable and flexible systems.
What Is EDA?
Event-Driven Architecture (EDA) is an architectural style where components communicate through events. When something happens (order placed, payment received), interested services listen and react.
Traditional: Order Service → Call Payment → Call Inventory → Call Notification
EDA: Order Service → Publish "OrderPlaced"
↓
Event Bus
↓ ↓ ↓
Payment Inventory Notification
EDA Components
Event
A record of something that happened:
interface OrderPlacedEvent {
eventType: 'OrderPlaced';
timestamp: string;
data: {
orderId: string;
customerId: string;
items: Array<{ productId: string; quantity: number }>;
totalAmount: number;
};
}
Producer, Consumer, Channel
- Producer — Service that emits events
- Consumer — Service that listens and reacts
- Channel — Infrastructure that carries events (Kafka, RabbitMQ)
EDA Patterns
1. Event Notification
Just "something happened." Consumer queries the source for details.
2. Event-Carried State Transfer
All relevant data included in the event. No additional queries needed.
3. Event Sourcing
Store all events instead of current state. Rebuild state by replaying events.
Event 1: OrderCreated { id: 123, items: [...] }
Event 2: PaymentReceived { id: 123, amount: 1500 }
Event 3: ShipmentSent { id: 123, trackingId: "TR123" }
→ Current state: Order 123, Paid, Shipped
Practical Example
Producer
class OrderService {
async placeOrder(customerId: string, items: CartItem[]) {
const order = Order.create(customerId, items);
await this.orderRepo.save(order);
await this.eventBus.publish({
eventType: 'OrderPlaced',
data: { orderId: order.id, customerId, items, totalAmount: order.total }
});
return order;
}
}
Consumer
class NotificationService {
@OnEvent('OrderPlaced')
async handle(event: OrderPlacedEvent) {
await this.emailService.send({
to: event.data.customerId,
template: 'order-confirmation',
data: { orderId: event.data.orderId }
});
}
}
Eventual Consistency
In EDA, data becomes consistent eventually, not immediately. This is a deliberate trade-off for decoupling and scalability.
When to Use EDA
✅ Multiple services react to the same event | ✅ Loose coupling needed | ✅ Audit trail required
❌ Simple CRUD apps | ❌ Strong consistency required | ❌ Few services
Best Practices
- Idempotent consumers — Handle duplicate events gracefully
- Schema versioning — Version your event schemas
- Dead Letter Queue — Isolate failed events
- Correlation ID — Track events across services
- Monitor event lag — Alert on growing consumer lag
Conclusion
EDA provides loose coupling, scalability, and flexibility for distributed systems. The eventual consistency trade-off is worth it when applied correctly.
Learn event-driven architecture on LabLudus.