What Is an E-commerce Checkout System?
The checkout system orchestrates the final steps of an online purchase: cart validation, inventory reservation, payment processing, order creation, and fulfillment initiation. It is one of the highest-stakes flows in e-commerce: any failure or slowness directly impacts revenue. At Amazon scale: millions of checkouts per hour during peak events (Prime Day, Black Friday).
Checkout Flow
- Cart validation: verify all items still exist, have the displayed price, and quantity is available
- Inventory reservation: temporarily hold the requested quantity to prevent overselling during payment processing
- Payment authorization: charge the customer’s payment method
- Order creation: create a confirmed order record, release the inventory reservation, deduct from inventory
- Fulfillment trigger: publish order to fulfillment service (warehouse, shipping)
Inventory Reservation (Soft Hold)
Between checkout start and payment completion, inventory must be held to prevent overselling the same item. Soft hold: reserve inventory for 10–15 minutes while customer completes payment. If payment fails or times out, the hold is released.
BEGIN TRANSACTION;
SELECT quantity FROM inventory WHERE sku = ? FOR UPDATE;
IF quantity < requested: ROLLBACK; return "Out of Stock";
UPDATE inventory
SET quantity = quantity - requested,
reserved = reserved + requested
WHERE sku = ?;
INSERT INTO holds (sku, quantity, order_id, expires_at)
VALUES (?, requested, ?, NOW() + INTERVAL 15 MINUTES);
COMMIT;
A scheduled cleanup job releases expired holds: UPDATE inventory SET reserved=reserved-quantity, quantity=quantity+quantity_held WHERE expired holds. This prevents inventory being stuck in hold forever if a customer abandons checkout.
Idempotent Order Creation
Network failures during payment can leave the system in an ambiguous state: did the payment succeed? Was the order created? Use an idempotency key (checkout_session_id) to guarantee at-most-once order creation. Before creating the order, check if an order with this checkout_session_id already exists. If yes, return the existing order. This allows safe retry of the entire checkout without double-orders or double-charges.
Order State Machine
PENDING → PAYMENT_AUTHORIZED → CONFIRMED → SHIPPED → DELIVERED
→ PAYMENT_FAILED → CANCELLED
→ CANCELLED (user cancels before shipment)
→ RETURN_INITIATED → RETURNED
Atomic state transitions via UPDATE orders SET status=? WHERE id=? AND status=expected_current_status. Optimistic locking: if the UPDATE affects 0 rows, another process already changed the state — handle accordingly.
Preventing Oversell at Scale
At high concurrency (Black Friday surge), FOR UPDATE creates lock contention on hot items. Alternative: optimistic locking with check-and-decrement:
UPDATE inventory
SET quantity = quantity - requested
WHERE sku = ? AND quantity >= requested;
affected_rows = check result;
IF affected_rows == 0: return "Out of Stock";
No explicit lock — the WHERE clause is the check. Two concurrent updates: one succeeds, one gets affected_rows=0 (quantity already depleted). For very hot items: use a Redis atomic counter: DECRBY inventory:{sku} requested — if result < 0, INCRBY to restore and return out-of-stock. Redis single-threaded atomicity eliminates race conditions.
Promo Codes and Discounts
Apply promo codes before payment authorization. Validate: code exists, not expired, usage limit not exceeded, applicable to items in cart. Increment usage count atomically (Redis INCR + compare to limit) before proceeding to payment — prevents race condition where two users simultaneously apply the last use of a promo code.
Interview Tips
- Soft hold is the central inventory design — inventory reserved but not deducted until order confirmed.
- Idempotency key on checkout_session_id prevents double-orders on payment retry.
- Redis for hot inventory items — contention on PostgreSQL FOR UPDATE at Black Friday scale is problematic.
- State machine with atomic transitions prevents illegal state transitions (can’t ship a cancelled order).
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How do you prevent overselling inventory during high-traffic events like Black Friday?”,
“acceptedAnswer”: { “@type”: “Answer”, “text”: “Overselling occurs when concurrent buyers all read "quantity=1" and all proceed to checkout before any decrement is committed. Three approaches: (1) Pessimistic locking: SELECT … FOR UPDATE locks the inventory row. First transaction acquires lock, others wait. Guarantees no oversell but creates serialization bottleneck on hot items. Appropriate for low-to-moderate concurrency. (2) Optimistic locking: UPDATE inventory SET qty=qty-N WHERE sku=? AND qty>=N. No lock — the WHERE clause is the guard. If 0 rows affected, qty was insufficient. Works well under moderate contention; high contention causes many failed updates and retries. (3) Redis atomic decrement: DECRBY inventory:{sku} N → if result < 0, INCRBY to restore and return out-of-stock. Redis is single-threaded — all commands are serialized without explicit locks. Best for high-throughput hot items (viral products, flash sales). Complement with async DB sync: Redis is the real-time inventory counter; MySQL is the system of record updated asynchronously (or via a CDC stream).” }
},
{
“@type”: “Question”,
“name”: “How does a soft hold (inventory reservation) work in checkout?”,
“acceptedAnswer”: { “@type”: “Answer”, “text”: “A soft hold reserves inventory between checkout initiation and payment completion — preventing the same unit from being purchased by two customers simultaneously. Flow: when customer initiates checkout, decrement available_qty and increment reserved_qty for each cart item. If payment succeeds within the timeout window: confirm the reservation (deduct from reserved_qty, create order). If payment fails or checkout is abandoned: release the hold (restore reserved_qty back to available_qty). Implementation: holds table with (sku, quantity, checkout_session_id, expires_at). A background job runs every minute: DELETE expired holds, restore inventory. Or use Redis with TTL: SETEX hold:{sku}:{session_id} 900 {quantity} (15-minute TTL). On timeout: Redis auto-expires the key, a background worker detects missing keys and restores inventory. The soft hold window must be long enough for payment processing but short enough to not block inventory for too long (15 minutes is typical).” }
},
{
“@type”: “Question”,
“name”: “How do you handle the Saga pattern in a distributed checkout flow?”,
“acceptedAnswer”: { “@type”: “Answer”, “text”: “In a microservices checkout, steps span multiple services: inventory service (reserve), payment service (charge), order service (create), fulfillment service (ship). A single database transaction cannot span services. The Saga pattern: decompose the checkout into a sequence of local transactions, each with a compensating transaction for rollback. Choreography-based saga: each service publishes events; the next service listens and triggers its step. If a step fails, it publishes a failure event; upstream services execute their compensating transactions. Example: inventory_reserved event → payment_service charges → payment_succeeded event → order_service creates order. If payment fails: payment_failed event → inventory_service releases hold. Orchestration-based saga: a central orchestrator (checkout service) calls each step and explicitly handles failures by calling compensating actions. More control but a single point of failure. At Shopify/Amazon scale: orchestration-based is preferred because it makes the workflow explicit and observable. The checkout service becomes a state machine tracking which steps have completed.” }
}
]
}