All system design challenges
#64 Two-Phase Commit/Saga

Shopify Inventory Reservations

Hold stock for a customer during checkout across separate inventory, order and payment services, and release it cleanly if anything fails.

Asked at Shopify

What is being asked

Design inventory reservation for an e-commerce platform. Checkout touches several services with their own databases; either all steps happen or the stock goes back. This is the standard setting for comparing two-phase commit with sagas.

Requirements

Functional

  • Reserve stock when checkout starts; confirm on payment; release on failure or timeout.
  • Never sell more than is in stock.

Non-functional

  • Services are independent, each with its own database.
  • High traffic during sales; partial failures are normal.
  • A stuck checkout must not hold stock for ever.

Design

reserve / releasecharge / refundCheckoutOrder service (sagaorchestrator)Inventory servicePayment serviceShipping serviceInventory DB:available, reservedSaga logMessage bus
Boxes are services; rounded shapes are data stores and queues.
  1. Inventory keeps two numbers per item: available and reserved. Reserve is an atomic conditional update: move the quantity from available to reserved only if enough is available.
  2. The order service runs a saga: reserve stock, charge payment, create the shipment. Each step is a local transaction in one service.
  3. If a step fails, the orchestrator runs the compensating actions for the steps already done, in reverse: refund the payment, release the reservation.
  4. The saga's progress is recorded in a log, so after a crash it resumes or compensates.
  5. Each reservation has an expiry; a sweeper releases those never confirmed.

Key decisions and trade-offs

  • Two-phase commit gives atomicity across services, but participants hold locks while waiting for the coordinator, and a coordinator failure blocks them. It suits a few databases under one team, not many independent services.
  • Sagas never hold cross-service locks and tolerate failures, but there is no isolation: other requests see intermediate states, such as stock that is reserved but not yet paid for. The design must make those states meaningful.
  • Orchestration or choreography. A central orchestrator makes the flow explicit and easy to trace. Services reacting to each other's events are more loosely coupled but the overall flow becomes hard to see.
  • Idempotent steps and compensations. Every command may be delivered twice, so each carries the saga id and is applied once.

Follow-up questions

  • What if the compensating refund itself fails?
  • How do you size the reservation timeout?
  • How would you stop a flash sale from overselling under this design?
  • What does the customer see while the saga is in progress?
Log in to tick off the challenges you have worked through. Log in