Event-Driven Architecture
Event-driven architecture (EDA) is a pattern where services communicate by producing and consuming events, rather than calling each other directly. Producers emit events ('user created', 'order placed') without knowing who consumes them. This enables loose coupling, easy extensibility, and independent scaling.
How it works
In a traditional request-response architecture, service A calls service B: POST /users {name: 'Ada'}. B processes and returns. If you later add an analytics service that also needs to know about new users, you must modify A to also call analytics.
In event-driven architecture, A emits an event: event: UserCreated {id: 42, name: 'Ada'}. A message broker routes it to any subscriber. Analytics, email, audit, and recommendation services all subscribe independently — A doesn't know or care who consumes the event.
There are two types of messages in EDA:
- Events (facts): 'UserCreated', 'OrderPlaced'. Past tense, immutable. The producer doesn't expect a response. Multiple consumers can react independently.
- Commands (requests): 'SendEmail', 'ChargeCard'. Imperative, directed. The producer expects something to happen. Usually one consumer.
Events enable true decoupling. Commands are closer to RPC over a queue. Most systems use both: events for broadcasting facts, commands for requesting specific actions.
EDA is inherently eventually consistent. When you emit 'UserCreated', the email service might process it 100ms later. During that window, the user exists but hasn't received a welcome email. This is usually fine — but if your UX requires immediate consistency (e.g., 'you can't proceed until the email is sent'), EDA is the wrong choice.
Benefits of EDA:
- Loose coupling: producers don't know consumers. Add/remove consumers without touching producers.
- Independent scaling: each consumer scales independently based on its own load.
- Resilience: if a consumer is down, events queue up (or are redelivered) — no data loss.
- Extensibility: add a new consumer (e.g., ML training pipeline) without modifying any existing service.
- Audit trail: events form an immutable log of what happened in the system.
The trade-off: eventual consistency, harder debugging (no single call stack), and the need for event schema management.
Your e-commerce system currently calls the email service synchronously when an order is placed. You want to add an analytics service that also needs to know about orders. What's the event-driven approach?
Pick one answer.
What is the difference between an event and a command in EDA?
Pick one answer.
Engineering mental model
Mental model. Think of Event-Driven Architecture as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Event-Driven Architecture mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing Event-Driven Architecture, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
message_id = queue.publish({
"type": "event-driven-architecture",
"key": resource_id
})
# Consumer must be safe to retry.Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: Event-Driven Architecture
Change the variables below and predict what breaks first in Event-Driven Architecture. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on Event-Driven Architecture, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using Event-Driven Architecture. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using Event-Driven Architecture?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses Event-Driven Architecture, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose Event-Driven Architecture, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
For Event-Driven Architecture, separate producer speed from consumer speed. The key design question is what happens when production temporarily exceeds processing capacity: queue it, shed it, slow producers down, or degrade the feature.
Numerical sanity check
A simple queue sanity check: if producers create 8,000 messages/s and consumers process 6,000 messages/s, backlog grows at roughly 2,000 messages/s until the imbalance is corrected.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
A downstream service slows down while Event-Driven Architecture keeps accepting traffic. Would you rather apply backpressure, queue more work, shed load, or degrade? Explain the trade-off.
Pick one answer.
What you gain, what you pay
- +Loose coupling — add/remove consumers without touching producers.
- +Independent scaling — each consumer scales on its own.
- +Resilience — consumers can be down without losing events.
- +Extensibility — new consumers subscribe without code changes.
- +Audit trail — events form an immutable log.
- −Eventual consistency — consumers process asynchronously, not immediately.
- −Harder debugging — no single call stack; distributed tracing needed.
- −Event schema evolution — changing event structure breaks consumers.
- −Infrastructure complexity — message broker, event registry, schema management.
How this breaks in production
- Event schema changes break consumers — use schema registry and versioning.
- Consumer falls behind — queue grows, events are delayed (mitigated by auto-scaling + alerting).
- Duplicate events — consumers must be idempotent (at-least-once delivery).
- Circular event chains — service A emits event, B consumes and emits another, which causes A to emit again... (mitigated by careful event design).
Don't fall into these traps
- •Treating events as commands — expecting a response or directing them at a specific consumer.
- •Not versioning event schemas — a field rename breaks all consumers.
- •Making events too granular — 'UserFieldUpdated' for every field change floods the system.
- •Forgetting eventual consistency — assuming all consumers have processed the event immediately.
Real systems using this
How real systems implement this
- Netflix — Hundreds of microservices communicate via events on Kafka. The 'user played a movie' event triggers recommendations, billing, and analytics — all independently.
- Uber — Domain events (trip requested, driver assigned, trip completed) flow through Kafka to dozens of consuming services. Each domain owns its events.
Practice saying it out loud
- Q1What is event-driven architecture? How does it differ from request-response?
- Q2What's the difference between an event and a command?
- Q3How do you handle event schema evolution?
- Q4When would you NOT use EDA?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Publish/Subscribe (Pub/Sub)