Most enterprise systems communicate through direct calls - one system sends a request to another and waits for a response. This works until the number of systems grows, until some of them are slow, or until one goes down and takes others with it.
Event-driven architecture is the alternative. Instead of systems calling each other, they publish events to a broker, and other systems subscribe to those events. The publisher doesn't wait for anyone. Subscribers process events at their own pace.
This communication model is called publish/subscribe. This article explains when and why you'd choose it over direct calls.
Cascading failures
The first thing that breaks with direct calls is availability. A loan origination platform chains three services: credit scoring, fraud detection and compliance verification. Each call is synchronous - the application waits for credit scoring to respond before calling fraud detection, then waits again before calling compliance.
When the credit scoring provider has a slow day (and they do), fraud detection and compliance are blocked even though they have nothing to do with the delay. Meanwhile, new loan applications keep arriving, each one spawning its own chain of blocked calls. Within minutes the whole pipeline is stalled.
With EDA, the loan application publishes one event: loan.application.submitted. Credit scoring, fraud detection and compliance each subscribe independently. If credit scoring is slow, fraud detection and compliance still process the application on their own timeline. No chain, no cascade.
When a call times out
Even when the cascade doesn't happen, individual calls still fail. When a REST call times out, you don't know whether the other side processed it or not. You're left choosing between retrying (and risking duplicates) or not retrying (and risking data loss).
With a message broker in the middle, this problem disappears. The publisher sends the event to the broker and gets an acknowledgement. From that point, the broker is responsible for delivering it to subscribers. If a subscriber is temporarily offline, its queue holds the message until it comes back. The publisher's job is done.

System integration at scale
Failures aside, direct calls also create a maintenance problem that grows with every new system. An insurance company has four core systems: policy management, claims processing, billing and CRM. Each team built their system independently over different years, using different technologies.
The traditional approach is point-to-point integrations. Policy management calls claims, claims calls billing, billing calls CRM. With 4 systems, that's 6 integration points. Add a fifth system and it's 10. Add a tenth and it's 45. Each new integration means coordinating two teams, agreeing on an API contract, handling failures on both sides, and maintaining the connection forever.
With EDA, each system publishes events about what it does: policy management publishes policy.issued and policy.cancelled, claims publishes claim.filed and claim.settled, and so on. Any system that needs to react subscribes. Ten systems no longer require 45 integrations - each one connects to the broker and subscribes to the topics it cares about.
Adding a new analytics platform doesn't require touching existing systems. It subscribes to the events it needs and starts processing them. The integration count grows linearly, not quadratically.
Legacy systems
The integration problem gets worse when some of the systems involved can't be changed. Most organizations run critical business logic on systems older than their newest developers. You can't replace them because they work, because migration is too risky, or because nobody fully understands what they do anymore.
But you need them to participate in modern workflows. Your mainframe needs to send data to your current services. Your SAP installation from 2010 needs to trigger workflows in newer applications. Your on-premises database needs to feed your analytics platform.
Traditional integration creates adapters per connection: mainframe-to-REST, SAP-to-JSON, database-to-API. When you modernize the REST API, you update every adapter that calls it. When a new system needs mainframe data, you write another adapter.
EDA uses a different pattern. You write one adapter per legacy system - not one adapter per integration. The mainframe adapter publishes events whenever customer data changes. It doesn't know who consumes them. Your services subscribe. Your analytics platform subscribes. When you add a new system that needs customer data, you don't touch the mainframe adapter. The new system just subscribes to customer events.
This is how organizations modernize without a risky full rewrite: they wrap legacy systems in event publishers and let newer systems consume what they need.
Traffic spikes and system downtime
So far the examples assumed steady traffic. What happens when load is uneven? An e-commerce platform runs a flash sale. Order volume jumps to 5x the normal rate within seconds. The payment gateway, inventory system and shipping service all need to process each order.
With synchronous calls, the order service calls each one in sequence. If the payment gateway can't keep up, orders start failing. If inventory is down for a deployment, the whole checkout flow breaks.
With EDA, the order service publishes order.placed and moves on. The payment gateway, inventory and shipping each consume from their own queues at whatever rate they can sustain. During the spike, queues grow. After the spike, they drain. If inventory is offline for a deployment, its queue accumulates orders and processes them when it comes back. No orders are lost, no checkout flow breaks.
Message priority
Queues solve the volume problem, but not all messages are equally urgent. A payment processing system handles thousands of transactions per hour. Most are routine settlements that can be processed in bulk. But some are fraud alerts that need immediate attention - a suspicious transaction must be flagged before the next one goes through.
With direct calls processed in arrival order, a fraud alert waits behind hundreds of routine settlements. By the time it's processed, three more suspicious transactions have already cleared.
A message broker solves this with message priorities. When a fraud alert is published with high priority, it moves ahead of the routine settlements already in the queue. The payment processing team defines priority levels per topic - fraud alerts at the top, time-sensitive refunds in the middle, batch settlements at the bottom. Each subscriber's queue respects these priorities, so the most critical work is always handled first regardless of when it arrived.

External dependencies
Everything discussed so far involved systems you control. The picture changes when third-party services enter the mix. Your billing system needs to send invoice PDFs to customers via a third-party email API. The API is slow, sometimes times out, and occasionally goes down for maintenance.
If you call it synchronously, your invoice generation is blocked on an external service you don't control. A 30-second timeout from the email API means your billing workers are idle for 30 seconds per failed invoice.
If you publish an invoice.generated event instead, a separate worker picks it up and calls the email API. If the API fails, the worker retries later. Your invoice generation completes immediately regardless of what the email service is doing. Internal processes never block on external dependencies.

EDA and SOA together
EDA doesn't replace the service-oriented approach - it extends it. Service-oriented architecture and event-driven architecture work together. Services expose operations through well-defined interfaces for synchronous use. The same services can also publish events when their state changes, letting other systems react asynchronously.
A CreateAccount service, for example, creates the account synchronously and returns a response to the caller. It also publishes an account.created event. The billing system subscribes and sets up billing records. The notification system subscribes and sends a welcome email. The analytics system subscribes and updates growth metrics. The CreateAccount service doesn't know about any of them.
FAQ
1. What is the difference between EDA and request-response?
Request-response is synchronous - the caller waits. EDA is asynchronous - the publisher moves on immediately and subscribers process events independently.
2. When should I use EDA?
When you have multiple systems that need to react to the same events. When traffic is unpredictable. When downstream systems are sometimes slow or offline. When you're integrating systems built by different teams or vendors.
3. Does EDA replace REST APIs?
No. REST APIs are still the right choice for synchronous operations where the caller needs an immediate response. EDA handles the cases where the caller doesn't need to wait and where multiple systems need to react to the same event. Most architectures use both.
4. What happens if a subscriber is offline?
Its message queue holds events until it comes back. The publisher is not affected and other subscribers continue processing normally.




- John Adams