Most backend systems are designed as request/response pipelines because that is the shape APIs come in. The work I keep coming back to — payment IPN handling at ESOL, order processing on OrderX, swap workflows on the Web3 wallet platform — is awkward in a request/response shape. The submit path is small and synchronous; the processing is large and eventually consistent. Pushing them into the same request is what makes the platform fragile.
Event-driven architecture separates those two responsibilities. Submission becomes an append to a topic; processing becomes a consumer that owns its own retry, idempotency, and observability contract. The system gets slower at coordination and faster at recovery.
Where EDA wins
The first place EDA earns its complexity is anywhere the downstream processing is heterogeneous. A payment IPN triggers fee calculation, transaction persistence, risk evaluation, outbound notifications, and reconciliation reads. In a request/response system each of those steps is on the critical path; in an event-driven system, each one is its own consumer with its own lifecycle. Adding a new consumer is a deployable change, not a change to the API path.
The second place is anywhere the request is allowed to be slow as long as it does not fail. Order submission on OrderX can tolerate a few seconds of latency at the backend as long as the client gets an immediate acceptance. Decoupling submit from process is the only way to give the client the latency it needs without giving up the depth of processing required.
The third place is anywhere retry policy is workload-specific. Webhook deliveries want short, aggressive backoff; nightly reconciliation wants long delays and few attempts. Encoding the policy on the work — as you can in a queue — is cleaner than carrying it through a synchronous request.
Where EDA loses
Event-driven is the wrong choice when the caller genuinely needs the answer to make the next decision. A risk evaluation that gates whether a payment is allowed to proceed is not a great event-driven candidate; the caller needs the verdict. Forcing that flow through a topic turns a synchronous decision into a polling problem and pushes the real complexity into the client.
EDA is also the wrong choice for low-volume, low-fanout workflows where the operational cost of running a broker is greater than the value of decoupling. Kafka is not a free architectural choice, and a topic that has one producer and one consumer is usually a description of a function call.
The third failure mode is treating EDA as "fire and forget". Topics with no consumer group, no dead-letter handling, and no replay tooling are not event-driven systems; they are message queues with abandonment problems.
Backpressure is the part people skip
A producer that can publish faster than consumers can process will eventually find the limit, and the limit is usually memory. The work that follows is unglamorous: per-partition concurrency caps, consumer lag as a first-class signal, and explicit decisions about what happens when lag crosses a threshold (reject new submissions, scale consumers, or pause the producer).
Backpressure that the system does not acknowledge is what turns a Kafka cluster into a debugging story.
Consistency is eventual; design for it
The hardest engineering consequence of EDA is that the same logical event shows up in different stores at different times. The order is visible in the topic before it is visible in the read store; the read store shows the order before the search index does; the search index shows the order before downstream caches warm. Every consumer needs to be honest about which "view" of the world it owns.
Idempotency keys are how the system reconciles. A consumer that crashes between processing and commit becomes a producer that retries, and the only way to keep the side-effect count honest is to make the consumer's side-effect idempotent at the storage layer.
When to choose
Pick EDA when the submit path can be small, the processing can be slow, and the fan-out is the point. Pick request/response when the caller's next decision depends on the answer and the workflow has one natural owner. The interesting systems mix both shapes — a synchronous API in front of an asynchronous interior — and the work is to make the seam between them explicit rather than accidental.