Event-Driven Architecture
Event-driven architecture (EDA) is a design approach where components communicate by producing and consuming events — records of something that happened. Instead of direct API calls, services publish events to a broker, and interested consumers react asynchronously.
What is an Event?
An event is a notification that something happened: OrderPlaced, UserRegistered, PaymentProcessed. Events are immutable facts — they describe the past, not a request for future action. This distinction matters: a command asks a service to do something; an event tells the world that something already happened.
Event Producers and Consumers
A producer publishes events without knowing who will consume them. Consumers subscribe to the events they care about. This decoupling means the producer does not need to know about the consumer's existence. New consumers can be added without changing the producer — a powerful property for evolving systems. Events are typically serialised as JSON; validate their structure with the JSON Formatter.
Message Queues vs Pub/Sub
A message queue (RabbitMQ, SQS) delivers each message to exactly one consumer — useful for work distribution. Pub/sub (Kafka topics, SNS, Google Pub/Sub) delivers each message to all subscribers — useful when multiple systems need to react to the same event. Many architectures combine both: pub/sub for broadcasting events, queues for distributing work within a single consumer group.
Apache Kafka
Kafka is a distributed event streaming platform that combines pub/sub with durable, ordered log storage. Producers write events to topics, which are partitioned for parallelism. Consumers read from partitions at their own pace using offsets. Kafka retains events for a configurable period (or forever with compaction), making it possible to replay history — essential for rebuilding state and debugging. Use the Timestamp Converter to decode Kafka message timestamps during debugging.
Patterns: Event Sourcing
Event sourcing stores every state change as an immutable event rather than overwriting a database row. To get the current state, you replay all events. This provides a complete audit trail and enables time-travel debugging. It is powerful but complex — you need projection logic, snapshotting for performance, and careful schema evolution for event versions.
Patterns: CQRS
Command Query Responsibility Segregation separates the write model (handling commands) from the read model (optimised for queries). Events bridge the two: the write side publishes events, and the read side projects them into query-optimised views. CQRS is often combined with event sourcing but can be used independently.
Trade-offs and Challenges
EDA introduces eventual consistency — consumers process events asynchronously, so there is a window where data is stale. Debugging is harder because a single business operation spans multiple services and events. Ordering guarantees vary by broker: Kafka guarantees order within a partition; SQS does not guarantee order at all (unless you use FIFO queues). Idempotency is critical — consumers must handle duplicate events gracefully. Inspect event payloads during debugging by pasting them into the JSON Formatter and use the Code Diff to compare event schema versions.
When to Use EDA
EDA shines when you need loose coupling between services, asynchronous processing, or a reliable audit trail. It is a natural fit for e-commerce (order → payment → shipping), IoT (sensor events), and real-time analytics. It is overkill for simple CRUD applications where synchronous REST calls are simpler and easier to reason about.