Reliable systems / Hypothetical examples

Keep a Bookstore Order Consistent When One Service Fails

Follow a fictional order across stock reservation, payment authorization and confirmation, including timeouts and compensating actions.

By Sandeep Belgavi · Published 28 October 2026 · Educational guide

Give every order one durable intent

Belgavi's Book Store is fictional and every record in this guide is synthetic. A reader submits a cart. The order service records an intent before contacting stock and payment services. It keeps the cart revision, amount, currency and a stable operation key. Retrying the same request returns the same intent rather than starting a second order.

Reserve stock, authorize payment, then confirm the order. Each service commits its own local transaction. The coordinator records which steps completed and which are uncertain. A single database transaction does not automatically extend across independent services.

Treat a timeout as an unknown outcome

Suppose payment authorization succeeds but the response is lost. The coordinator must query the payment service using the existing operation key. Repeating authorization under a new key can reserve funds twice. A timeout is evidence about the response path, not proof that the action failed.

Keep pending work visible. A reconciliation worker can retry the lookup with bounded backoff and a deadline. If the result remains uncertain, retain the order in a review state rather than sending a confident confirmation or silently discarding the intent.

Define compensation before the happy path

If payment is definitively rejected after stock was reserved, release that reservation. If confirmation cannot proceed after authorization, void the authorization when that operation is supported. Compensation is a new action with its own outcome; it does not erase the earlier action from history.

For each step, record its idempotency key, evidence and compensation status. Make repeated release or void requests safe. Some effects cannot be reversed exactly. A confirmation message already delivered can be followed by a correction, but cannot be made unread.

Test crashes at every durable boundary

Use synthetic orders and stop the coordinator after each recorded transition. Restart it and verify that confirmed steps are not repeated under new keys. Inject duplicate callbacks, reordered events and an unavailable reconciliation service. Assert the durable stock and payment states as well as the response shown to the reader.

The shared-state lab demonstrates why concurrent branches can lose updates. It is a computed teaching fixture, not a live commerce backend. Its arithmetic is useful for finding a race, while a deployment also needs service-level integration tests.

Further reading

The saga pattern guidance explains coordination and compensation across local transactions. The bookstore scenario is an original hypothetical example.