Skip to main content
SDMastery
intermediate9 min readUpdated 2026-06-03

Event-Driven Architecture

EDA enables loose coupling, scalability, and real-time processing. It is the architecture behind real-time analytics, IoT systems, and modern.

Event-Driven Architecture system design overview showing key components and metrics
High-level overview of Event-Driven Architecture
Event-Driven Architecture

What Event-Driven Architecture Actually Means

Event-driven architecture (EDA) is a design pattern where the flow of the program is determined by events — significant changes in state. Components produce events (order placed, payment received), and other components consume them asynchronously. This decouples producers from consumers and enables reactive, scalable systems.

When to Use It (and When Not To)

Event-Driven Architecture system architecture with service components and data flow
System architecture for Event-Driven Architecture

EDA enables loose coupling, scalability, and real-time processing. It is the architecture behind real-time analytics, IoT systems, and modern microservices platforms. In interviews, understanding EDA shows you can design beyond simple request-response systems.

The Architecture

When a user places an order: the Order Service publishes an 'OrderPlaced' event to Kafka. The Payment Service consumes the event and charges the customer. The Inventory Service consumes it and reserves items. The Notification Service sends a confirmation email. Each service processes independently and at its own pace.

If the Payment Service is temporarily down, events queue up in Kafka and are processed when it recovers. No data is lost.

Step-by-step diagram showing how Event-Driven Architecture works in practice
How Event-Driven Architecture works step by step

Key Principles

  • Events: Immutable records of something that happened. 'OrderPlaced', 'PaymentFailed', 'UserRegistered'.
  • Producers and Consumers: Producers emit events; consumers react to them. They do not know about each other.
  • Event broker: A middleware (Kafka, RabbitMQ, AWS EventBridge) that stores and routes events between producers and consumers.
  • Event sourcing: Store all changes as a sequence of events. Rebuild state by replaying events. Used by banking systems.
  • CQRS: Command Query Responsibility Segregation — separate the write model (commands) from the read model (queries). Often paired with event sourcing.

Who Does This Well

LinkedIn processes billions of events per day through Kafka for activity feeds, recommendations, and analytics.

Comparison table for Event-Driven Architecture showing key metrics and tradeoffs
Comparing key aspects of Event-Driven Architecture

Uber uses an event-driven architecture for ride matching, pricing, and driver dispatch.

Netflix uses event-driven patterns for content recommendation, A/B testing, and user activity tracking.

The Hard Parts Nobody Talks About

  1. Not versioning events — schema changes break consumers
  2. Not handling out-of-order events — network delays can deliver events in wrong order
  3. Over-using events for everything — simple synchronous calls are sometimes better
Data flow diagram for Event-Driven Architecture showing request and response paths
Data flow through Event-Driven Architecture

The Tradeoffs

  • Decoupling vs Debugging: EDA decouples services but makes it harder to trace the flow of a request.
  • Eventual consistency: Events are processed asynchronously, so the system is eventually consistent — not immediately.
  • Complexity: Event schemas, ordering, deduplication, and dead letter queues all add complexity.

Interview Angles

  1. What is event-driven architecture?
  2. What is the difference between event-driven and request-driven architecture?
  3. What is event sourcing?
  4. What is CQRS?
Key components of Event-Driven Architecture with roles and responsibilities
Key components of Event-Driven Architecture

Keep Learning

The Real-World Incident That Made This Famous

Interview tips for Event-Driven Architecture system design questions
Interview tips for Event-Driven Architecture

The most dramatic example of event-driven architecture in production is the global banking system's adoption of event sourcing. In 2012, LMAX Exchange (a London-based financial exchange) published their Disruptor pattern, showing how an event-driven architecture could process 6 million transactions per second on a single thread. The key insight was treating every state change as an immutable event in a sequential log, eliminating the need for locks and enabling replay of the entire system state from the event log.

But the incident that really made engineers pay attention to event-driven pitfalls was the Knight Capital disaster of August 2012. A deployment error activated old trading code on their event-driven trading platform. The system processed events (market data feeds) and generated automated trading orders. The stale code generated millions of unintended orders in 45 minutes, resulting in a $440 million loss. Knight Capital went bankrupt within days. The root cause was not the event-driven architecture itself — it was that an event-driven system processes events automatically and at machine speed, so a bug in the event processing logic can cause damage much faster than a human can intervene.

This incident drove the industry to implement safeguards in event-driven systems: circuit breakers on event processing rates, anomaly detection on output event volumes, human-in-the-loop approval for actions above certain thresholds, and the ability to pause event processing without losing events (which event sourcing enables naturally since events are persisted).

How Senior Engineers Think About This

Decision guide showing when to use Event-Driven Architecture and when to avoid
When to use Event-Driven Architecture

Think of event-driven architecture as the difference between a restaurant where the waiter stands by your table waiting for your order (request-driven) versus a restaurant with a buzzer that notifies you when your food is ready (event-driven). In the event-driven model, services react to things that have happened (events) rather than being told what to do (commands).

The three patterns that senior engineers distinguish: Event notification (Service A publishes "OrderPlaced" and does not care who receives it — pure decoupling), Event-carried state transfer (the event contains the full state, like "OrderPlaced with items, prices, addresses" so receivers do not need to call back to Service A), and Event sourcing (the event log IS the source of truth — current state is derived by replaying all events).

Event sourcing is the most powerful but also the most complex pattern. Instead of storing "account balance = $500," you store "deposited $1000, withdrew $300, deposited $100, withdrew $300." The current balance is derived by replaying these events. This gives you a complete audit trail, the ability to reconstruct state at any point in time, and the ability to replay events to fix bugs or populate new read models. Banks, trading systems, and compliance-heavy systems use event sourcing heavily.

The CQRS (Command Query Responsibility Segregation) pattern often accompanies event-driven architectures. Writes go to the event store (append-only, optimized for writes). Reads come from materialized views built by projecting events (optimized for queries). This separation allows you to scale reads and writes independently and optimize each for its access pattern.

Pros and cons analysis of Event-Driven Architecture for system design decisions
Advantages and disadvantages of Event-Driven Architecture

Common Interview Mistakes

Mistake 1: Using event-driven everywhere. Not every interaction benefits from async events. User login should be synchronous — the user needs to know immediately if they are authenticated. Use events for operations where the caller does not need an immediate result.

Mistake 2: Confusing events with commands. An event describes something that HAS happened ("OrderPlaced"). A command requests something to happen ("PlaceOrder"). This distinction matters for system decoupling.

Mistake 3: Not discussing eventual consistency. Event-driven systems are inherently eventually consistent. If a user places an order and immediately views their order history, the order might not appear yet. Discuss how to handle this (read-your-own-writes, polling, optimistic UI updates).

Real-world companies using Event-Driven Architecture in production systems
Real-world examples of Event-Driven Architecture

Mistake 4: Ignoring event schema evolution. As your system evolves, event schemas change. Old events in the log still need to be readable. Discuss versioning strategies: schema registry, upcasting, or tolerant readers.

Mistake 5: Not mentioning idempotency. Events may be delivered more than once. Every event handler must be idempotent — processing the same event twice should produce the same result as processing it once.

Production Checklist

  • Design events as immutable facts about what happened — include all relevant data, not just IDs
  • Implement idempotent event handlers using deduplication keys (event ID + handler name)
  • Use a schema registry to manage event schema versions and ensure backward compatibility
  • Monitor event processing lag: the time between event publication and consumption by each subscriber
  • Implement dead letter queues for events that fail processing after retries
  • For event sourcing: implement snapshots every N events to avoid replaying the entire event history on startup
  • Build monitoring dashboards that show event flow rates between services — visualize the event topology
  • Implement correlation IDs that flow through the entire event chain for distributed tracing
  • Plan for event replay: you should be able to rebuild any read model by replaying events from the beginning
  • Test eventual consistency scenarios: what does the user experience when reads lag behind writes?

Read the original source | Content from System-Design-Overview

Practical Implementation for .NET Developers

In a .NET application, you would typically implement this pattern using the following approach:

ASP.NET Core setup: Create a service class that encapsulates the logic, register it with dependency injection, and inject it into your controllers or minimal API endpoints. The built-in DI container handles lifecycle management.

Entity Framework Core: For database interactions, EF Core provides the ORM layer. Use migrations for schema management and raw SQL for performance-critical queries. Consider Dapper for read-heavy paths where EF Core's overhead matters.

Azure integration: If deploying to Azure, leverage managed services — Azure Cache for Redis, Azure SQL, Azure Service Bus, Azure Cosmos DB. These eliminate operational overhead and provide built-in monitoring through Application Insights.

Testing: Use xUnit with Testcontainers for integration tests that spin up real databases in Docker. Mock external dependencies with NSubstitute. The WebApplicationFactory class lets you test your entire HTTP pipeline in-process.

Monitoring: Add Application Insights telemetry to track request latency, dependency calls, and custom metrics. Use structured logging with Serilog to make production debugging possible:

text
Log.Information("Processing order {OrderId} for {CustomerId}", orderId, customerId);

This gives you searchable, structured logs in Azure Monitor or Seq.

External Resources

Original Sourcearticle