Building an e-commerce store (Amazon)
Implement atomic inventory decrement that prevents overselling, the cart store, and the checkout saga with reservations and compensations.
Inventory: the atomic decrement (no overselling)
The core correctness operation — only sell if stock remains, atomically:
-- succeeds only if enough stock; returns 0 rows if not → reject the order
UPDATE inventory
SET available = available - :qty
WHERE sku = :sku AND available >= :qty
RETURNING available;
Because the DB applies this atomically, concurrent buyers of the last unit can’t both
succeed — one update finds available >= qty false. This conditional decrement is the
anti-oversell guarantee.
Reserve-and-confirm (better checkout UX)
For a smoother flow, reserve stock during checkout and confirm on payment:
def reserve(sku, qty, order_id):
ok = db.execute(DECREMENT_SQL, sku=sku, qty=qty) # move to "reserved"
if not ok: raise OutOfStock()
reservations.put(order_id, sku, qty, expires=now()+15*60) # hold; auto-release
def release_expired(): # job scheduler
for r in reservations.expired(): restock(r.sku, r.qty) # return abandoned holds
Cart store
Per-user, fast, persistent; re-validated at checkout (never trust cart prices/stock):
def add_to_cart(user, sku, qty):
cart_kv.update(user, lambda c: {**c, sku: c.get(sku, 0) + qty}) # KV store, per user
def checkout(user):
cart = cart_kv.get(user)
items = revalidate(cart) # current price + availability NOW
return start_order_saga(user, items)
The checkout saga
Coordinate inventory, payment, and order creation with idempotent steps + compensations:
def start_order_saga(user, items):
order = orders.create(user, items, state="placed")
Saga(order.id, [
Step("reserve_inventory", reserve_all, release_all),
Step("authorize_payment", auth_payment, void_auth),
Step("create_order", finalize, cancel_order),
Step("capture_payment", capture, refund),
]).run() # persisted/resumable; compensate on any failure
enqueue_fulfillment(order.id) # async shipping after payment
return order.id
The order is a durable state machine (placed → paid → shipped → delivered), advanced by
events idempotently — a crash resumes, never double-charges.
Catalog, search, recommendations (read path)
- Product pages denormalized, cached, and CDN’d (mostly static); sharded by product id.
- Search via an inverted index with facets (Chapter 4 search), updated async from the catalog.
- Recommendations precomputed (collaborative filtering) and served from a fast store.
Scale and failure handling
- Browse/search (read-heavy) → cache + CDN + replicas + index; the dominant traffic.
- Hot SKU at a flash sale → the atomic decrement serializes per-SKU (bottleneck); shard inventory by SKU, use atomic counters, and queue/throttle if needed.
- Payment fails → saga compensates (release inventory, void auth).
- Crash mid-checkout → saga resumes from persisted progress (idempotent).
- Peak events → autoscale stateless services; pre-warm caches; the CP inventory path is the scaling pressure point.
The takeaway
Concrete signals: the conditional atomic decrement (or reserve-and-confirm) that makes overselling impossible, a per-user cart re-validated at checkout, and a durable order saga with compensations. Read-heavy catalog (cache/CDN/index) split from a CP inventory/order path is the e-commerce blueprint — and the payment step deserves its own design, next.