Skip to content

Metadata Card

  • Prerequisites: Chapter 13 (Microservices Migration); Understanding ACID transactions
  • Estimated Time: 50 minutes
  • Core Difficulty: Advanced
  • Completion Milestone: Design Saga (choreography/orchestration), understand CQRS and Event Sourcing use cases

Your Progress

Micro-engines are running. Each engine has its own data warehouse — Score Engine has its own ledger, Match Engine has its own match records.

Now your "create tournament" flow needs to: write a record in Match Engine, notify Score Engine to initialize scores for participants. In the single-machine era, add a lock. Now it spans two independent engines and two ledgers. Your Task

Distributed data consistency isn't a "should I use ACID" question — in distributed environments, traditional ACID transactions are either unavailable or too expensive. This chapter covers four common patterns.

Required reading: Saga (orchestration), Transactional Outbox Selective: CQRS Advanced: Event Sourcing


First Layer: Saga — Long-Running Transaction

Break a large transaction into a series of local transactions, each within its own service. If a step fails, execute compensating actions.

Choreography Saga: Each service publishes events triggering the next step. No central coordinator.

Orchestration Saga: An orchestrator tells each service what to do, manages compensation centrally.

Second Layer: CQRS — Command Query Responsibility Segregation

Separate read models from write models. Write uses one model (commands), read uses another (often pre-joined materialized views).

Third Layer: Event Sourcing

Store events, not current state. Current state is computed by replaying events. Provides full audit trail and time travel capabilities.

Fourth Layer: Transactional Outbox

Write the message to a database "outbox" table within the same transaction as the business operation. A separate process reads from the outbox and sends to the message queue.

sql
CREATE TABLE outbox_messages (
    id UUID PRIMARY KEY,
    event_type VARCHAR(100) NOT NULL,
    payload JSONB NOT NULL,
    status VARCHAR(20) DEFAULT 'PENDING',
    retry_count INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW()
);

Common Pitfalls: Incomplete Saga compensation, CQRS read model lag, Event Sourcing schema evolution, Dead Letter not handled in outbox.


Traveler's Notes

Cross-service data consistency is a long war — Saga replaces rollback with compensation, CQRS arms reads and writes differently, Event Sourcing makes events a time capsule, Outbox ensures messages don't get lost. No silver bullet, but patterns to follow.


Next: Deployment & Operations Patterns (Chapter 16).

Built with VitePress | Software Systems Atlas