Event-Driven Architecture
Event-driven architecture (EDA) centers on producing, routing, and consuming events — immutable records that something happened (OrderPlaced, PaymentCaptured, DriverLocationUpda…
Introduction
Event-driven architecture (EDA) centers on producing, routing, and consuming events — immutable records that something happened (OrderPlaced, PaymentCaptured, DriverLocationUpdated). Producers don't know consumers; the event broker decouples teams and absorbs traffic spikes.
EDA excels at fan-out (one order triggers email, analytics, warehouse, loyalty), temporal decoupling, and audit trails. Trade-offs include eventual consistency, duplicate delivery handling, and debugging complexity across async flows.
This lesson teaches event naming, broker selection, consumer design, and how EDA complements request-response APIs in HLD interviews.
Understanding the topic
Key concepts
- Event: past-tense fact with schema (Avro/JSON Schema/Protobuf) and metadata (timestamp, correlationId).
- Event notification vs event-carried state transfer — choose based on consumer autonomy.
- Broker: Kafka for log-based replay; RabbitMQ/SQS for task queues; Redis Streams for lighter cases.
- At-least-once delivery typical — consumers must be idempotent.
- CQRS often pairs with EDA: write model emits events; read models project asynchronously.
- Choreography (consumers react) vs orchestration (central saga coordinator).
flowchart LRProducer -->|event| BrokerBroker --> ConsumerABroker --> ConsumerB
Internal architecture
Architecture overview
flowchart LRProducer -->|event| BrokerBroker --> ConsumerABroker --> ConsumerB
Step-by-step explanation
- Command API accepts user action → persists aggregate → publishes domain event to broker.
- Topic partitioned by aggregate ID (orderId) preserving per-entity ordering.
- Multiple consumer groups read same topic independently (notifications vs BI).
- Dead-letter queue (DLQ) captures poison messages after retry exhaustion.
- Schema registry enforces compatible event evolution.
- Observability: trace context propagated in event headers (OpenTelemetry baggage).
Informative example
Publish inventory adjustment events after stock update — downstream search index updates asynchronously:
@Servicepublic class InventoryService {private final InventoryRepository repo;private final KafkaTemplate<String, StockAdjustedEvent> kafka;public InventoryService(InventoryRepository repo, KafkaTemplate<String, StockAdjustedEvent> kafka) {this.repo = repo;this.kafka = kafka;}@Transactionalpublic void adjust(String sku, int delta) {Inventory inv = repo.findBySku(sku).orElseThrow();inv.apply(delta);repo.save(inv);kafka.send("inventory.stock-adjusted", sku,new StockAdjustedEvent(sku, inv.quantity(), Instant.now()));}}public record StockAdjustedEvent(String sku, int quantity, Instant at) {}@Componentclass SearchIndexConsumer {@KafkaListener(topics = "inventory.stock-adjusted", groupId = "search-index")public void project(StockAdjustedEvent e) {// upsert Elasticsearch document — idempotent by sku}}
Name events in past tense. Include correlationId from HTTP request in Kafka headers for end-to-end traces.
Real-world use
Real-world use cases
- E-commerce order pipeline fan-out to warehouse, email, fraud, analytics.
- Banking ledger posting triggering compliance audit and customer notification.
- Social graph: new post event updates follower feeds and search index.
- Healthcare HL7/FHIR change events syncing EHR modules.
Best practices
- Design idempotent consumers with natural keys or idempotency store.
- Version event schemas with backward-compatible rules.
- Use outbox pattern to atomically DB-write + publish.
- Monitor consumer lag — primary EDA health metric.
- Keep events small; reference large blobs by URL/id.
- Document event catalog — who publishes, who subscribes, SLA.
Common mistakes
- Using events for synchronous query/response — wrong tool.
- No DLQ — poison messages block partition processing.
- Assuming exactly-once without transactional outbox or idempotent design.
- God topics with unrelated events — hard to scale and govern.
- Missing ordering guarantees where business requires per-entity sequence.
Advanced interview questions
Q1BeginnerWhat is event-driven architecture?
Q2BeginnerBenefit of EDA over direct HTTP calls?
Q3IntermediateHow handle duplicate events?
Q4IntermediateOutbox pattern purpose?
Q5AdvancedDesign EDA for food order lifecycle.
Summary
EDA decouples services through immutable domain events. Kafka enables replay, fan-out, and high-throughput logs. Design for at-least-once with idempotent consumers. Outbox pattern bridges transactional writes and publishing. Pair events with CQRS for read model projections. Layered and scaling lessons build on these integration patterns.