Event-Driven Architecture: How Modern Businesses Build Real- Time Software
A deep dive into the principles, patterns, and engineering decisions that power modern reactive systems — from asynchronous messaging to change data capture.
From Request-Response to Signals of Change
Traditional software architectures are built around synchronous request-response interactions where one service directly calls another and waits for a reply. Event-Driven Architecture (EDA) fundamentally changes this relationship. Instead of requesting action, systems publish signals that something has changed, allowing downstream consumers to react independently, asynchronously, and at scale.
A Fundamental Shift in Coordination
The Old Model: Request-Response
Service A calls Service B directly, waits for a response, and cannot continue until that response arrives.
• Caller blocks until response returns
• Failures propagate through dependencies
• One slow service impacts the entire flow
• Scaling often requires scaling multiple connected systems
The New Model: Asynchronous Events
Services publish events describing state changes while consumers independently decide whether and when to react.
• No blocking or waiting
• Failures remain isolated
• Systems scale independently
• New consumers can be added without modifying producers
Why Event-Driven Systems Scale Better
Request-Response Challenges
• Latency accumulation
• Tight dependencies
• Reduced resilience
• Harder horizontal scaling
Event-Driven Advantages
• Independent scaling
• Buffered workloads
• Greater resilience
• Easier system evolution
Events Represent Facts, Not Requests
The most important mindset shift in EDA is that systems stop asking other services to perform actions. Instead, they announce that something happened. Consumers independently determine whether that event matters and what action, if any, should follow.
Publish Changes. Let Systems React.
Event-Driven Architecture replaces tightly coupled conversations with streams of business facts. By embracing timeliness, asynchrony, and fine-grained events, organizations create systems that are more scalable, more resilient, easier to evolve, and better equipped to handle the complexity of modern distributed applications.
An event records something that already happened. It is not an instruction for the future. That distinction determines how systems publish, consume, replay, audit, correct, and evolve data.
Events are timestamped records with unique identifiers. After publication, the original fact remains unchanged; a correction is represented by a new event.
An append-only event history supports state reconstruction, projection rebuilding, audit trails, debugging, and controlled recovery from consumer failures.
Published events should express a stable business fact, not expose every field in a producer’s database or internal aggregate.
Large payloads create accidental schema coupling: every consumer starts depending on fields that were never meant to be public.
Identifies the service or system that produced the event, supporting filtering and auditability.
States the semantic meaning of what happened and acts as a primary routing key.
Carries the identifiers consumers need to find related context without duplicating the full record.
Use a unique event ID and timestamp for deduplication, ordering analysis, and idempotent handling.
A standardized envelope makes event metadata predictable across producers, brokers, and consumers.
Publish facts in the past tense, keep them immutable, append corrections as new facts, and keep payloads lean enough to preserve consumer independence. The event log becomes powerful when history can be trusted, replayed, understood, and evolved without silently rewriting the past.
The First Aha: Events Are Immutable Facts
Append, Never Rewrite
Replay and Reconstruct
Do Not Expose Internal State
Carry Meaning, Not the Whole Database
Source
Type
Business IDs
ID & Time
CloudEvents-Style Metadata
"id": "uuid",
"source": "orders-service",
"type": "OrderCreated",
"time": "2026-08-18T06:52:00Z",
"data": { "orderId": "..." }
}id, source, and type as core event attributes; timestamps represent event-generation time when supplied. [268][275]The Event Principle
Event-driven systems unlock flexibility and resilience but introduce subtle problems absent in synchronous designs. Duplicates, out-of-order delivery, and consistency gaps are the hidden villains. Ignoring them risks double charges, corrupted analytics, and phantom inventory. Production-grade EDA requires explicit defenses.
Event-driven systems are inherently eventually consistent. Different components may briefly hold different truths — this is the trade-off enabling scalability and resilience.
Duplicates, ordering, and consistency are not bugs — they are realities of distributed messaging. Engineering for them transforms EDA from fragile prototypes into production-grade systems capable of handling scale and complexity safely.
The Hidden Villain: Duplicates, Ordering & Consistency
Duplicates: They Will Happen. Design for It.
Ordering: Don't Assume It, Engineer It
Consistency Trade-offs
Key Insight
Publishing events is only the beginning of a production-grade Event-Driven Architecture. True resilience emerges from the infrastructure surrounding those events: intelligent routing, durable storage, delivery guarantees, and workflow coordination models that continue operating despite failures, deployments, network interruptions, or consumer outages.
Directs events to the appropriate destinations using routing and filtering logic without requiring producers to know who consumes the event.
Preserves event history as a durable, ordered log that supports replay, recovery, auditing, and rebuilding downstream systems.
Defines what guarantees exist regarding event delivery, duplication handling, and fault tolerance behavior.
Traditional queues remove messages after successful delivery. Event stores preserve events as durable logs, creating a permanent historical record of business activity.
Use choreography for independent, parallel reactions to business events. Use orchestration when workflows require coordination, rollback capabilities, process visibility, and explicit state management. The most successful event-driven platforms employ both patterns strategically rather than treating them as mutually exclusive choices.
Event-Driven Architecture achieves resilience not through messaging alone, but through the combined power of intelligent routing, durable event storage, deliberate delivery guarantees, and well-chosen coordination models. When these layers work together, systems become scalable, recoverable, observable, and capable of sustaining change without sacrificing reliability.
Resilience by Design: Event Routers, Stores & Delivery Semantics
The Foundation of Reliable Event Processing
Event Router
Event Store
Delivery Semantics
Event Store: The System Memory
Choosing the Right Coordination Model
Combine the Strengths of Both Models
Reliability Is an Architectural Decision
Change Data Capture connects relational databases to event-driven systems by reading committed changes from the database log instead of asking application code to perform a fragile dual write.
If application code writes to a database and then separately publishes an event, either operation can succeed while the other fails. Log-based CDC observes the committed database change as the authoritative source.
Logical decoding translates low-level log records into logical inserts, updates, and deletes. The CDC reader runs asynchronously, allowing consumers to process changes without application polling.
A CDC stream can feed search indexes, caches, analytics, warehouses, notifications, and other services without adding separate polling jobs for every destination.
A lightweight PostgreSQL logical-decoding option for low infrastructure overhead and a small number of consumers. Validate current plugin support and benchmark results for your workload.
A strong fit for multiple consumers, durable topics, consumer groups, replay, and cross-language integration. Kafka is at-least-once by default; end-to-end exactly-once requires careful transactional and idempotent design. [285][294]
A fit when downstream behavior depends on derived conditions or continuous queries, allowing change events to be emitted when query results change rather than exposing every raw row mutation. [283]
Prefer a direct, minimal pipeline when one consumer and low operational overhead matter most.
Use a durable event platform when many consumers need independent offsets and historical replay.
Push filtering and aggregation toward the stream-processing layer when raw row noise would burden consumers.
Reported figures depend on database settings, payload size, connector configuration, broker topology, batching, workload, and measurement boundaries.
Keep the database transaction authoritative, capture committed changes from its log, and choose the broadcast layer according to consumer count, replay needs, latency, and query complexity. CDC is not simply a faster polling loop—it is a deliberate bridge from transactional truth to reliable event distribution.
Real-Time in Practice: Capture Change and Broadcast It
Avoid the Dual-Write Gap
Decode Changes Asynchronously
Broadcast to Many Consumers
Choose the CDC Shape, Not Just the Tool
Trade-Offs at a Glance
Latency Numbers Are Not Universal
The CDC Principle
What's Your Reaction?