MicroservicePatterns.com

Suggestions

  • PagePattern catalogAll patterns by category.
  • LabCircuit Breaker and Retries labCrash a dependency and tune the breaker.
  • LabSaga labFail a step and watch the compensations run.
  • PagePractice questionsScenario questions with explanations.
  • PageDesign reviewCheck your own architecture for anti-patterns.
Data management

CQRS and Event Sourcing Lab

A shop runs a one-minute sale. Checkouts write orders while dashboards, search and each customer's “My orders” page read them. Keep everything in one model, or split reads from writes and feed a read model from events. Then fix a bug in that read model and find out whether its history can be rebuilt.

Background: CQRS, Event Sourcing, Transactional Outbox.

Scenarios
Data model

Checkouts, dashboards, search and "My orders" all use one orders database.

Load
Share of the database they use. Orders get the rest.
Ready
CheckoutwritesDashboardsand search: 60%Orders databaseone modelMy ordersalways current
–Checkouts timed out
–Read model behind (no separate one)
–Customers who could not see their new order
–Revenue report wrong by
sale0 s10 sRead model lag (one model: none)0%100%Checkouts succeeding
Guided experiments

Run these in order

  1. Share one model

    Checkouts, dashboards and search use the same database. Outside the sale it copes. When three times the usual orders arrive at 0:15, the reports leave too little room for writes: checkouts slow to the two-second timeout and about a fifth of them fail. Drag the report load to 0% to see that the reports are the problem.

  2. Split reads from writes

    CQRS: checkouts write to their own store, and a projector copies each change into a read model for the reports. No checkout fails now. But one projector applies 30 events a second, the sale makes 66, and the read model falls about 24 seconds behind. Most customers open “My orders” and their order is not there, long after the sale ends.

  3. Scale the projector

    Run three projector instances. They keep up with the sale and the read model stays half a second behind. Try two: the backlog still builds a little. Size the read side for the peak, and watch its lag as closely as you watch errors.

  4. Read your own writes

    Back to one projector, but “My orders” shows a customer's new order from the write side until the read model has it. Every customer sees their own order. The dashboards are still 24 seconds behind: this hides the lag where people notice it most, but it does not remove it.

  5. Fix a bug in a read model

    The revenue projection has always counted cancelled orders as sales. A fix is deployed at 0:20, so new cancellations are counted correctly. But the write side keeps only the current rows, and the events were thrown away once delivered. The old figures cannot be recomputed, and the report stays about $38,000 too high.

  6. Rebuild from the events

    Event sourcing: every change is kept as an event in an event store. When the fix is deployed, a new read model is built next to the old one by replaying all 9,000 old events, and it takes over once it has caught up. The report is right again about ten seconds later. Try it with one projector: the replay takes most of the minute.

  7. Replay events from an old format

    The oldest events use the first version of OrderPlaced, which called the amount “total”. The fixed projection only understands the current version, so the replay stops at the very first event and the report stays wrong. Now tick “Upcast version 1 events”: old events are converted as they are read and the replay works. Stored events are never edited, so every version ever written must stay readable.

This lab simplifies reality on purpose. Traffic is flat apart from the sale, every event costs the projector the same, and a rebuild replays one event store into one read model. Real systems partition the event stream so projectors scale, take snapshots so aggregates load quickly, and monitor read model lag as a service level of its own.