Mnemosyne

Event-Driven Architecture

Designing systems around events, messages, and asynchronous communication.

Core Concepts

Event-driven architecture (EDA) is a design pattern where system components communicate by producing and consuming events — records of something that happened.

Producer
Event Broker
Consumer A
Consumer B

An event is an immutable fact: "OrderPlaced", "UserRegistered", "PaymentProcessed". Events describe what happened, not what to do (that's a command).

Event Types

Domain Events

Represent meaningful business occurrences. Example: OrderShipped { orderId, trackingNumber, timestamp }.

Integration Events

Cross service boundaries. Published to a message broker for other services to consume. Keep these backward-compatible.

Event Notifications

Thin events that signal something happened without full details. Consumers call back for details if needed. Reduces coupling but increases chattiness.

Messaging Patterns

Publish-Subscribe

Producers publish events to a topic; all subscribers receive a copy. Decouples producers from consumers — producers don't know who's listening.

Point-to-Point (Queue)

Each message is consumed by exactly one consumer. Used for task distribution (work queues). Multiple consumers compete for messages.

Event Streaming

Events are written to an ordered, persistent log (e.g., Kafka). Consumers read at their own pace and can replay from any point. Events are retained, not deleted after consumption.

Event Sourcing

Instead of storing current state, store every state change as an event:

Command
Event Store
Projection
Read Model
AccountCreated { id: 1, name: "Alice" }
MoneyDeposited { id: 1, amount: 100 }
MoneyWithdrawn { id: 1, amount: 30 }
→ Current balance: 70

Pros: complete audit trail, time-travel debugging, can rebuild state from events. Cons: complexity, eventual consistency, event schema evolution.

CQRS

Command Query Responsibility Segregation separates the write model from the read model:

  • Command side: handles writes, validates business rules, emits events
  • Query side: maintains denormalized read models optimized for specific queries

Often paired with event sourcing: commands produce events, events update read models.

Saga Pattern

Coordinates long-running transactions across multiple services:

Choreography

Each service listens for events and reacts. No central coordinator. Simple but hard to track the overall flow.

Orchestration

A central saga orchestrator tells each service what to do. Easier to understand and monitor, but introduces a single point of coordination.

Both approaches use compensating transactions to undo completed steps when a later step fails.

Idempotency

Events may be delivered more than once (at-least-once delivery). Consumers must be idempotent — processing the same event twice should produce the same result. Common approach: track processed event IDs and skip duplicates.

Review Questions