Event-driven architecture vs. request-response — what changes in how you design a system?
Request-response couples services through direct calls and shared availability; event-driven architecture couples them only through the shape of events, trading immediate consistency for resilience and independent scaling.
LEARN BY DOINGPut your intuition to work3 steps
Event-driven architecture vs. request-response — what changes in how you design a system?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.Request-response and event-driven are two different answers to the same question: how does a service tell another part of the system what to do or what happened. The choice isn't cosmetic — it changes coupling, failure behavior, consistency guarantees, and how hard the system is to debug six months from now.
#Request-response: direct, synchronous, tightly coupled
In a request-response design, a caller sends a request to a specific service and blocks until it gets a reply. The caller knows exactly who it's talking to (an address, a hostname, a service name), and both sides must be available and healthy at the same instant for the call to succeed. Chain enough of these calls together — API gateway calls the order service, which calls inventory, which calls payment — and you get a synchronous call chain: the total latency is the sum of every hop, and the availability of the whole chain is the product of each service's individual availability. A hiccup three services deep surfaces immediately to the original caller as a timeout or a 5xx.
That immediacy is also request-response's biggest advantage: the caller gets a definitive answer in the same interaction — "your order was created" or "your card was declined" — with no ambiguity about whether the operation happened.
#Event-driven: indirect, asynchronous, loosely coupled
In an event-driven design, a service publishes an event — a fact about something that already happened, like OrderCreated — to a broker (Kafka, RabbitMQ, SNS/SQS, etc.) without knowing or caring who, if anyone, will react to it. Interested services subscribe independently. The producer's job ends the moment the event is durably published; it doesn't wait for, or even know about, downstream processing.
This is what decouples the services: Order Service has no compile-time or runtime dependency on Inventory, Payment, or Notification — it only depends on the shape of the event it publishes. You can add a fifth subscriber tomorrow without touching Order Service at all. That's the structural win, and it's why event-driven architectures scale organizationally as well as technically: teams can own a consumer without needing a change from, or coordination with, the producing team.
#What you give up: consistency and easy answers
The trade-off is consistency and immediacy. The client in the diagram above gets a 202 Accepted, not a confirmation that the order actually succeeded end-to-end — inventory might turn out to be insufficient two events later. The system becomes eventually consistent: correct once all the relevant events have propagated and been processed, but not correct at any single instant you can point to. That forces real design decisions the request-response version didn't: what does the UI show while the order is "pending"? What happens if PaymentFailed arrives after InventoryReserved — do you need a compensating action (release the stock)? This is the seed of the saga pattern, where a sequence of local transactions coordinated through events (or an explicit orchestrator) replaces one big distributed transaction.
| Dimension | Request-response | Event-driven |
|---|---|---|
| Coupling | Tight — caller knows the callee's address and must call it directly | Loose — producer only depends on the event schema, not on any consumer |
| Availability | Product of every hop's uptime; one down service breaks the chain | Producer's uptime alone; consumers can lag or restart without affecting it |
| Consistency | Strong, immediate — you know the outcome before the call returns | Eventual — correctness arrives after propagation and processing |
| Failure isolation | Poor — failures cascade and amplify (timeouts stack up) | Good — a slow/down consumer just grows a backlog, not an outage |
| Debuggability | Easier — one call stack, one trace | Harder — causality is spread across producers, consumers, and time |
| Best fit | Anything needing an immediate, authoritative answer (auth, payment authorization) | Fan-out, workflows spanning many services, anything that tolerates a short delay |
Most real systems are not purely one or the other. A typical service exposes a synchronous API for anything a client needs an immediate answer to (checking an order's status, authorizing a payment) and emits events for anything else can react to independently and asynchronously (sending a confirmation email, updating a recommendation model, syncing a data warehouse). The skill being tested in this question isn't "which one is better" — it's recognizing which parts of a given workflow genuinely need an immediate, consistent answer, and which parts are better served by a fact broadcast to whoever cares.