Design a flash sale system

A hundred times the normal traffic for ten minutes and a thousand items: how to avoid overselling and still keep the site alive.

On the roadmap:Interview Ready · step 5: Real-world designs

Lesson 6 of 18 · 11 min read · quiz · exercise

The problem

A flash sale sells a small number of items at a special price for a short time. Traffic is spiky: 100x or more of normal load for a few minutes, mostly from people refreshing the page.

Requirements

  • Never oversell: exactly the available quantity is sold.
  • Stay up: the rest of the site must keep working.
  • Be fair and resist bots.
  • Fast feedback: users should quickly learn whether they got one.

Why the naive version fails

stock = db.read("phone")      -- 1000 requests read 1
if stock > 0:
    db.write("phone", stock-1) -- 1000 requests write 0

Many requests see stock = 1 at once, and every one of them "succeeds". The database is also hammered by half a million reads. Two separate problems: correctness (races) and load (spike).

Before: everyone hits the database

After: layers shed load first

What changed

  • The CDN and edge absorb most of the clicks
  • A fast counter decides who gets stock, not the database
  • Orders are written at a pace the database can handle

Layered defence: shed load early

Figure SDA-RWS-06-1 · Flash sale: layers that shed load · © forcsguy.com

  1. CDN serves the sale page, images and scripts. Only the "buy" action reaches your servers.
  2. Edge protection: rate limit per user and IP, block known bots, require a challenge for suspicious clients.
  3. Waiting room: users get a place in line and are admitted at a controlled rate matching what checkout can take.
  4. Stock gate: an in-memory atomic counter (Redis DECR, or a Lua script that checks and decrements together) answers "did you get one?" in microseconds, and rejects the rest at once.
  5. Order queue: winners go onto a queue; the order service processes them at its own pace.
  6. Database is the final source of truth, using a conditional update (UPDATE ... SET stock = stock - 1 WHERE stock > 0) so it can never go negative even if the gate misbehaves.

Warehouse stock: the physical counterpart of the inventory count that must never go below zeroImage: Barry Bahler · Public domain · Source · Wikimedia Commons: FEMA - 37526 - Florida Logisitics Response center

Holds and payment

Payment takes time and can fail. When a user wins a slot:

  • Create an order in a pending state and hold the item for a short time (for example 10 minutes).
  • If payment succeeds, confirm the order. If the timer expires or payment fails, release the item back to the gate so waiting users can have it.

Correctness details

  • Idempotency: an order request carries a unique key, so a double-click or retry never creates two orders.
  • One per customer rules are checked at the gate with a per-user key.
  • Do not trust the gate alone: if the cache loses data, the database constraint still prevents overselling.
  • Reconcile counters with the database after the sale.

Operating it

  • Pre-warm: scale servers and caches before the start time; do not rely on reactive auto-scaling to catch a spike that arrives in one second.
  • Isolate: run the sale on its own stack or pool so it cannot take down the rest of the shop.
  • Degrade gracefully: turn off recommendations and non-essential features during the sale.
  • Load test beforehand with realistic bursts, and rehearse failure.
  • Use a kill switch and a clear "sold out" state so users stop retrying.

More on this site

Check your understanding

Question 1 of 3

0 correct so far

Why is reading the stock from the database and then decrementing it in application code dangerous during a flash sale?

Go deeper

© 2026 forcsguy.com. Original lesson text and diagrams. Books and sites linked above belong to their authors.