Skip to content

🚀 Event-Driven Architecture (EDA)

The Senior Mindset: EDA is a paradigm shift from Commands (“Do this”) to Events (“This happened”). A senior engineer uses EDA to build systems that are highly reactive, extensible, and capable of handling massive spikes in load by processing data asynchronously.


An immutable record of a past action. It contains the “State” or the “Change” that occurred.

  • Example: OrderPlaced, UserRegistered, PaymentFailed.
  • Producer: The service that detects a change and publishes an event. It doesn’t know (or care) who consumes it.
  • Consumer: The service that listens for specific events and reacts to them.

The infrastructure that carries events.

  • Message Queues: (e.g., RabbitMQ) Usually point-to-point; once a message is consumed, it’s gone.
  • Event Streams: (e.g., Kafka) A continuous log of events that can be replayed.

One producer sends a message that multiple consumers can receive.

  • Use Case: An OrderPlaced event triggers the Shipping Service, the Email Service, and the Inventory Service simultaneously.

Events are stored in an ordered log. Consumers can read the stream at their own pace.

  • Consumer Groups: Allow you to parallelize processing by spreading the stream across multiple instances.

⚖️ The Benefits & Challenges (The Senior Perspective)

Section titled “⚖️ The Benefits & Challenges (The Senior Perspective)”
  • Extreme Decoupling: Adding a new feature (like a “Loyalty Points” service) doesn’t require touching the “Order” service code. You just subscribe to the existing events.
  • Resilience: If the Email Service is down, the events wait in the broker. When the service comes back online, it processes the backlog without losing data.
  • Scalability: You can scale consumers independently based on the volume of specific events.
  • Eventual Consistency: Data isn’t updated everywhere instantly. You must design the UI and business logic to handle “in-flight” states.
  • Tracing & Debugging: It’s harder to follow a single “user journey” when it’s scattered across five services and a broker. (Solution: Use Correlation IDs).
  • Duplicate Events: Network issues can cause events to be sent twice.

Because “exactly-once” delivery is nearly impossible in distributed systems, every consumer must be idempotent.

  • Senior Strategy: Processing the same event twice should have the same result as processing it once (e.g., checking if a Transaction ID already exists in the DB before processing a payment).

How do you ensure that a Database update and an Event publication both happen (or both fail)?

  • The Problem: You save to the DB, but the broker is down. Now the DB is updated, but the rest of the system is out of sync.
  • The Solution: Save the event in a dedicated Outbox table in the same DB transaction as your business data. A separate “Relay” process polls that table and publishes to the broker.

When a consumer fails to process an event (e.g., due to a malformed payload), don’t let it block the whole queue.

  • Strategy: Move the “poison pill” message to a DLQ for manual inspection and let the consumer move on to the next event.

  • Event Sourcing: Instead of storing the current state of an object, you store every single event that led to that state. To get the balance of a bank account, you replay all Deposit and Withdrawal events.
  • CQRS (Command Query Responsibility Segregation): Separating the “Write” model (Events) from the “Read” model (Optimized materialized views).

💡 Seniority Note: Don’t go “Full Event-Driven” for everything. It introduces massive cognitive load. Use Request/Response for synchronous, user-facing actions where an immediate “Success/Fail” is needed. Use EDA for side effects, background processing, and inter-service communication.


  • [[Messaging-Kafka-vs-RabbitMQ]]
  • [[Microservices-Patterns]]
  • [[Architecture-Resilience-Patterns]]