How Event-Driven Architecture Works — Reacting Instead of Polling

How Event-Driven Architecture Works — Reacting Instead of Polling

2026-03-24

In a traditional request-driven system, service A calls service B and waits for a response. Service A knows about service B. If B is slow or down, A is affected. The two services are coupled in time, availability, and knowledge of each other.

Event-driven architecture inverts this. Instead of calling other services directly, a service emits an event describing what happened. Other services that care about that event react to it. The producer does not know who consumes its events, or even if anyone does.

Events, Commands, and Queries

These three concepts look similar but serve different purposes:

Event — a notification that something happened. Past tense. Immutable. "OrderPlaced", "UserRegistered", "PaymentFailed". The producer states a fact. It does not ask for anything.

Command — a request for something to happen. Imperative. "PlaceOrder", "SendEmail", "ChargeCard". Directed at a specific handler. Expects the handler to act.

Query — a request for information. "GetOrderById", "ListUsers". Expects a response. No side effects.

Events are the foundation of event-driven architecture. A service performs its work, commits its data, then emits an event. Downstream services subscribe to events they care about and react accordingly.

Producers and Consumers

An event producer is any component that emits events. The order service completes an order and emits OrderPlaced. It doesn't know or care what happens next.

An event consumer subscribes to events and processes them. Multiple consumers can react to the same event:

  • The inventory service receives OrderPlaced and decrements stock.
  • The email service receives OrderPlaced and sends a confirmation.
  • The analytics service receives OrderPlaced and updates dashboards.

Adding a new consumer does not require changing the producer. This is the core benefit: components are decoupled. The order service doesn't import the email service. It doesn't know the email service exists. You can add, remove, or replace consumers without touching the producer.

The Event Bus

Producers and consumers need something in between — an event bus or message broker that receives events from producers and delivers them to consumers.

Common implementations:

BrokerModelDurabilityUse case
Apache KafkaDistributed logEvents stored on disk, replayableHigh-throughput, event sourcing, streaming
RabbitMQMessage brokerMessages acknowledged and deletedTask queues, routing, RPC
Redis StreamsIn-memory logPersistent with append-only logLightweight streaming, real-time
Amazon SNS/SQSCloud-managedManaged durabilityAWS-native, fan-out + queue

The broker decouples producers from consumers in three ways:

  1. Time — the producer emits the event and moves on. The consumer processes it later, maybe seconds later, maybe hours later.
  2. Availability — if a consumer is down, the broker holds the event. When the consumer recovers, it catches up.
  3. Knowledge — the producer publishes to a topic. It does not address specific consumers.

Event-driven architecture: producer → bus → consumers

Order Service producer OrderPlaced Event Bus (Kafka, RabbitMQ, Redis Streams) Inventory decrement stock Email send confirmation Analytics update dashboard

Adding a consumer requires no changes to the producer

Eventual Consistency

In a request-driven system, you can wrap multiple operations in a transaction — either everything succeeds or nothing does. In an event-driven system, there is no single transaction boundary across services.

Instead, you get eventual consistency. The order service commits the order. It emits OrderPlaced. The inventory service eventually processes that event and decrements stock. Between the order being placed and the stock being decremented, the system is in an inconsistent state. The inventory count is temporarily wrong.

This is acceptable in most systems because the inconsistency window is small (milliseconds to seconds) and the tradeoff is worth it — services remain independent and available. A system that requires perfect consistency across services for every operation should probably not be split into microservices for those operations.

For a deeper treatment of consistency models, see How Consistency Works.

Event Ordering and Delivery Guarantees

Not all brokers provide the same guarantees:

At-most-once — the event is delivered zero or one times. If the consumer crashes before acknowledging, the event is lost. Fast but unreliable.

At-least-once — the event is delivered one or more times. If the consumer crashes before acknowledging, the broker redelivers. The consumer must be idempotent — processing the same event twice must produce the same result.

Exactly-once — the event is delivered exactly one time. Hard to achieve in distributed systems. Kafka provides exactly-once semantics within its ecosystem, but across system boundaries, at-least-once with idempotent consumers is the practical standard.

Ordering — Kafka guarantees ordering within a partition. RabbitMQ guarantees ordering within a single queue. Global ordering across all events is expensive and rarely necessary. Design for per-entity ordering (all events for order #123 arrive in order) rather than global ordering.

When to Use Event-Driven Architecture

Good fits:

  • Decoupling services that don't need synchronous responses.
  • Async processing — sending emails, generating reports, updating search indexes.
  • Audit trails — events are a natural log of everything that happened.
  • Multiple consumers need to react to the same occurrence.

Poor fits:

  • Operations that need an immediate, synchronous response (use REST or gRPC).
  • Simple CRUD applications where the overhead of a message broker is not justified.
  • Teams without the operational capacity to run and monitor a message broker.

The Pattern in Practice

A typical flow: a user places an order on an e-commerce site.

  1. The order service validates the request, writes the order to its database, and publishes OrderPlaced to the event bus.
  2. The payment service consumes OrderPlaced, charges the card, and publishes PaymentProcessed or PaymentFailed.
  3. The inventory service consumes OrderPlaced and reserves stock.
  4. The notification service consumes PaymentProcessed and sends a receipt.

Each service operates independently. If the notification service is down for maintenance, orders still process. When the notification service comes back, it catches up on missed events and sends the receipts.

Next Steps