पाठ 14 / 25
Design E-commerce Checkout and Inventory
Consistency, payments and idempotency.
Placing an order without overselling or double charging
Checkout touches cart, inventory, pricing, payment and orders. Two invariants matter: do not oversell stock and do not charge twice. For inventory, reserve stock with an atomic conditional decrement (UPDATE stock SET available = available - ? WHERE sku = ? AND available >= ?) when the order is created, and release the reservation if payment fails or times out. For payments, send an idempotency key with each charge so retries do not create a second charge; store the order in a PENDING state first and move it to PAID only after the payment provider confirms. Because this spans services, use a saga: a sequence of local transactions with compensating actions (release stock, refund) rather than a distributed transaction. Use an outbox table to publish events reliably alongside the database write.
Checkout saga
Order states and compensations.
POST /orders (Idempotency-Key: 7f3c...)
1. Order Service create order(PENDING) + outbox event OrderCreated
2. Inventory reserve items (conditional decrement)
fail -> order CANCELLED (out of stock)
3. Payment Service charge(amount, idempotency_key)
fail/timeout -> release reservation, order CANCELLED
4. Order Service order PAID -> ship workflow
Invariants
available >= 0 (enforced by conditional update)
one charge per idempotency key (provider + our payments table)
every state change has an event (transactional outbox)Reconcile payment status
A payment call can time out after the provider charged the card. Query the provider by idempotency key or rely on its webhook before deciding the order failed.
त्वरित जाँच: What prevents a retried payment request from charging the customer twice?
- Sharding the orders table
- A larger timeout
- Caching the product page
- An idempotency key sent with the charge
Answer
An idempotency key sent with the charge — Same key, same result.