Event-Driven Architecture
Designing systems around events, messages, and asynchronous communication.
Core Concepts
Event-driven architecture (EDA) is a design pattern where system components communicate by producing and consuming events — records of something that happened.
An event is an immutable fact: "OrderPlaced", "UserRegistered", "PaymentProcessed". Events describe what happened, not what to do (that's a command).
Event Types
Domain Events
Represent meaningful business occurrences. Example: OrderShipped { orderId, trackingNumber, timestamp }.
Integration Events
Cross service boundaries. Published to a message broker for other services to consume. Keep these backward-compatible.
Event Notifications
Thin events that signal something happened without full details. Consumers call back for details if needed. Reduces coupling but increases chattiness.
Messaging Patterns
Publish-Subscribe
Producers publish events to a topic; all subscribers receive a copy. Decouples producers from consumers — producers don't know who's listening.
Point-to-Point (Queue)
Each message is consumed by exactly one consumer. Used for task distribution (work queues). Multiple consumers compete for messages.
Event Streaming
Events are written to an ordered, persistent log (e.g., Kafka). Consumers read at their own pace and can replay from any point. Events are retained, not deleted after consumption.
Event Sourcing
Instead of storing current state, store every state change as an event:
AccountCreated { id: 1, name: "Alice" }
MoneyDeposited { id: 1, amount: 100 }
MoneyWithdrawn { id: 1, amount: 30 }
→ Current balance: 70
Pros: complete audit trail, time-travel debugging, can rebuild state from events. Cons: complexity, eventual consistency, event schema evolution.
CQRS
Command Query Responsibility Segregation separates the write model from the read model:
- Command side: handles writes, validates business rules, emits events
- Query side: maintains denormalized read models optimized for specific queries
Often paired with event sourcing: commands produce events, events update read models.
Saga Pattern
Coordinates long-running transactions across multiple services:
Choreography
Each service listens for events and reacts. No central coordinator. Simple but hard to track the overall flow.
Orchestration
A central saga orchestrator tells each service what to do. Easier to understand and monitor, but introduces a single point of coordination.
Both approaches use compensating transactions to undo completed steps when a later step fails.
Idempotency
Events may be delivered more than once (at-least-once delivery). Consumers must be idempotent — processing the same event twice should produce the same result. Common approach: track processed event IDs and skip duplicates.