Event-Driven Architecture (EDA) Design Pattern
I had a monolith where placing an order triggered a payment charge, an inventory update, an email notification, and an analytics event. All synchronous. A...
23 Mar 2024

I had a monolith where placing an order triggered a payment charge, an inventory update, an email notification, and an analytics event. All synchronous. All in one function. One slow email provider and the whole checkout hung for 30 seconds.
Event-Driven Architecture (EDA) fixes this by making components communicate through events instead of direct calls. The order service publishes an OrderPlaced event. Other services react to it independently. The order service doesn't know (or care) who's listening.
Think of it like a fire alarm. When it goes off, the building doesn't call each person individually. It broadcasts. People in different rooms react differently — some grab their bag, some check on others, some head to the exit. The alarm doesn't coordinate any of it.
Three Moving Parts
Event Producers generate events. A user clicks "Buy," the order service produces an OrderPlaced event.
Event Consumers subscribe to event types and react when they occur. The inventory service listens for OrderPlaced and reserves stock. The email service listens and sends a confirmation.
Event Bus / Broker is the delivery infrastructure. It routes events from producers to consumers, handles retries, and ensures reliability.
When EDA Fits
- Microservices. Services need to communicate without tight coupling. Events are the natural boundary.
- Real-time data processing. IoT streams, financial tickers, live dashboards.
- Workflow orchestration. Long-running processes with multiple steps across services.
- Systems that need to scale reads and writes independently. Pair EDA with CQRS and event sourcing.
Choosing a Message Broker
Apache Kafka. High throughput. Persistent log. Excellent for event sourcing and stream processing. But operationally complex — partitioning strategy matters, and consumer groups need careful design.
RabbitMQ. Mature. Supports multiple messaging patterns (pub/sub, work queues, routing). Easier to operate than Kafka for lower-throughput use cases. Not designed for event replay.
AWS Kinesis / SQS. Fully managed. Great if you're already on AWS. Kinesis for streaming, SQS for simple queuing. You trade control for operational simplicity.
The Gotchas
- Eventual consistency. Events are async. The order might be confirmed before inventory is updated. Your UI needs to handle this — "processing" states, optimistic updates, retries.
- Event ordering. Most brokers guarantee ordering within a partition, not globally. If order matters, design your partition key carefully.
- Debugging. A request touches five services via events. Tracing a bug requires distributed tracing (Jaeger, OpenTelemetry). Without it, you're blind.
- Schema evolution. Events are contracts. Changing an event shape can break consumers. Version your events from day one.
The benefit: Loose coupling. Independent scaling. Services can be deployed, scaled, and updated independently. Adding a new consumer doesn't require changes to the producer.
The cost: Operational complexity. You need monitoring for event lag, dead letter queues, and consumer health. Debugging distributed async flows is genuinely hard. And eventual consistency requires a mindset shift — both for developers and for UX design.
I use EDA in systems where services need to react to domain events without blocking each other. For simple request-response interactions within a single service, direct function calls are simpler and correct.
Keep reading
- Event Sourcing Checklist: When It Makes Sense & Common Pitfalls
- Error Boundary React Design Pattern
- Context API React Design Pattern
- Higher-Order Component (HOC) React Design Pattern
- Container Component React Design Pattern
- Best Practices for Structuring Express.js Applications with Prisma Design Pattern