Skip to main content

Classic design · Senior

Flash sale

Classic interview design. Key points: reservations and concurrency, and overload control.

16 min read · Content reviewed on October 23, 2026

Short answer

Classic interview design. Key points: reservations and concurrency, and overload control. The flash sale isolates one hard piece of e-commerce: selling a very limited quantity of stock under extreme demand. The goal is to let buyers compete fairly for the units and complete the purchase without ever selling beyond the stock.

01 · CONTEXT

Few units, many people

The flash sale isolates one hard piece of e-commerce: selling a very limited quantity of stock under extreme demand. The goal is to let buyers compete fairly for the units and complete the purchase without ever selling beyond the stock.

The flow gains a step between viewing the product and paying: reserving the unit. Payment goes through a third party and takes seconds, and stock cannot be held in an open database transaction for all that time. The reservation takes the unit out of circulation immediately and leaves the settling of the money for later.

The public material lists four deep dives that form the roadmap of this case: maintaining consistency under extreme contention, efficiently releasing expired reservations, handling millions of users arriving at once, and making access to limited stock fair.

02 · RACE

The counter that goes negative

The naive way to sell is to read the available count, check that it is greater than zero, and then decrement it. For a single buyer this is correct. With two buyers at the same instant, both read the same count, both conclude there is a unit to sell, and both proceed to charge the card.

When the two writes arrive, the first takes the count to zero and the second decrements again, and the count goes negative. The seller ends up with a refund to issue and two unhappy customers.

  1. Two buyers request the last unit almost at the same instant.

    Architecture diagram: Race on stock decrement
    CLComprador Awants the unit
    CLComprador Bwants the unit
    CPCheckout service
    DBInventory database
  2. Both requests read the same count and see one unit available.

    Architecture diagram: Race on stock decrement
    CLComprador A
    CLComprador B
    CPCheckout service
    DBInventory databaseone unit
  3. Each concludes there is a unit to sell and proceeds to the charge.

    Architecture diagram: Race on stock decrement
    CLComprador A
    CLComprador B
    CPCheckout servicedecides to sell
    DBInventory database
  4. The first write takes the count to zero and the second decrements again, leaving it negative.

    Architecture diagram: Race on stock decrement
    CLComprador A
    CLComprador B
    CPCheckout service
    DBInventory databasenegative count
  5. A single count row forces every checkout of the item to update the same row, which sets up the next section.

    Architecture diagram: Race on stock decrement
    CLComprador A
    CLComprador B
    CPCheckout service
    DBInventory databasesingle row

03 · HOT ROW

One row, one queue

In Hello Interview's description of the Shopify work, the obvious attempt in a relational database was one row per item with a quantity counter. Every checkout of a popular item had to update the same row, and InnoDB, MySQL's engine, grants the row lock to one transaction at a time, so the other buyers wait. Thousands of checkouts of the same item collapsed into a single lock.

The documented way out spreads the contention. To reserve units, the system selects and locks available rows and removes them from the pool. The SKIP LOCKED feature makes MySQL skip locked rows and look for another available one; this way, two buyers of the same item lock different rows and commit in parallel, instead of waiting behind a shared counter.

The gain has a limit. An item with a lot of stock could generate hundreds of thousands of nearly idle rows, so there is a cap on rows per item and a replenishment process that keeps the pool stocked.

  1. Two buyers of the same item arrive at checkout.

    Architecture diagram: Reservation per unit row with replenishment
    CLComprador Arequests reservation
    CLComprador Brequests reservation
    CPCheckout service
    DBStock and reservations database
    CPPool replenishment
  2. In a short transaction, checkout selects and locks available rows and removes them from the pool.

    Architecture diagram: Reservation per unit row with replenishment
    CLComprador A
    CLComprador B
    CPCheckout service
    DBStock and reservations databaselocks rows
    CPPool replenishment
  3. The second buyer skips over the rows already locked and locks others, without waiting.

    Architecture diagram: Reservation per unit row with replenishment
    CLComprador A
    CLComprador Bno waiting
    CPCheckout service
    DBStock and reservations databasedifferent rows
    CPPool replenishment
  4. The reservation is recorded as a row with a deadline, and locks exist only inside the short transactions that touch it.

    Architecture diagram: Reservation per unit row with replenishment
    CLComprador A
    CLComprador B
    CPCheckout service
    DBStock and reservations databasereservation with deadline
    CPPool replenishment
  5. A replenishment process keeps the pool stocked when it runs low.

    Architecture diagram: Reservation per unit row with replenishment
    CLComprador A
    CLComprador B
    CPCheckout service
    DBStock and reservations database
    CPPool replenishmentreplenishes rows
  6. A race can empty the pool before replenishment arrives; so the reservation itself refills the pool on the spot and tries again.

    Architecture diagram: Reservation per unit row with replenishment
    CLComprador A
    CLComprador B
    CPCheckout service
    DBStock and reservations databaseempty pool
    CPPool replenishment
AspectoSingle counterOne row per unit
How stock is storedOne row per item with a quantity counterAvailable rows that checkout locks and removes from the pool
Under contentionThousands of checkouts of the item collapse into a single lockBuyers lock different rows and commit in parallel
What you payEvery checkout of the item updates the same rowA new replenishment process to operate, monitor, and trigger, whose typical failure is the empty pool in the middle of the sale

04 · ATOMICITY

Counting in one place, selling in another

The same account shows why the counter may not be able to live outside the database that holds the stock. Previously, Redis recorded the temporarily reserved units and MySQL recorded the units the merchant actually had. As a concurrency mechanism, Redis worked, but the two writes happened in different databases and could not be committed together.

Both errors cost money: selling the last unit to two buyers forces canceling an order, and hiding a unit that is still in the warehouse makes the merchant lose a sale. If the system updates MySQL and crashes before clearing the reservation in Redis, the purchase is complete, but Redis still treats those units as reserved, and the system hides stock that is available. In the reverse order the error is the opposite: the reservation is cleared, the crash comes before the update, and the units go back on sale even though they are already sold. Swapping the order only changes which failure is possible.

O two-phase commit also doesn't work: it would require both databases to take part in the same coordination protocol, which Redis could not do.

05 · DEADLINE

Reservations nobody says have ended

Reserving is not buying. If payment fails or the buyer leaves checkout, there is an explicit signal that releases the reservation. If the buyer simply closes the laptop, no signal arrives, and, if nothing returns the units, the sale shows as sold out while the warehouse still has stock. That is why the deadline must live in the data, and something still running must act when it passes.

With a Redis counter, the tempting way out is a TTL, but a TTL on the counter key would delete the whole counter, not one buyer's reservation. A key per reservation doesn't help either: Redis has no fast way to get the count from a pile of per-reservation keys.

For the MySQL design, Hello Interview says the Shopify post does not say what it did and gives its own guess: store the reservation as a row with a deadline and count as active only the reservations that have not yet expired. Once the deadline passes, the reservation stops counting and the next replenishment returns the capacity. A cleanup routine is still desirable, but it is garbage collection, not correctness.

06 · ENTRY

The crowd before the database

Even a correct inventory design needs protection against millions of users arriving at once, which the material lists as a separate deep dive. A virtual waiting room routes the excess users to a custom queue, preserving the experience and protecting the origin servers from being overwhelmed with requests.

A well-built waiting room remembers each visitor's state, so that no one loses their place in the queue or has to re-enter if they leave the site, and it opens spots faster by tracking the flow in and out.

Besides the queue, the server itself needs to protect itself. Throughput is everything that arrives; goodput is the part handled without errors and with latency low enough for the client to make use of the response. Shedding load allows goodput to be maintained even when offered load grows, and rejecting early is the cheapest point to shed, at the cost of visibility.

  1. A crowd tries to open the sale at the same time.

    Architecture diagram: Admission before checkout
    CLCrowd of buyersmass arrival
    EDGWaiting room at the edge
    CPCheckout service
    DBInventory database
  2. The waiting room routes the excess users to a custom queue, instead of letting them reach the origin.

    Architecture diagram: Admission before checkout
    CLCrowd of buyers
    EDGWaiting room at the edgewaiting queue
    CPCheckout service
    DBInventory database
  3. The room keeps each visitor's state, so they hold their place in the queue.

    Architecture diagram: Admission before checkout
    CLCrowd of buyers
    EDGWaiting room at the edgeplace held
    CPCheckout service
    DBInventory database
  4. Only admitted traffic reaches checkout, which can still shed early whatever exceeds its capacity.

    Architecture diagram: Admission before checkout
    CLCrowd of buyers
    EDGWaiting room at the edge
    CPCheckout servicesheds excess
    DBInventory database
  5. The inventory database receives only the load left over after these layers.

    Architecture diagram: Admission before checkout
    CLCrowd of buyers
    EDGWaiting room at the edge
    CPCheckout service
    DBInventory databasecontrolled load

The public material treats fairness of access to limited stock as a separate deep dive, alongside consistency, reservation expiry, and the crowd.

Frequently asked questions

What is Flash sale?

Classic interview design. Key points: reservations and concurrency, and overload control.

What does the Flash sale design cover?

It is organized in these sections: Few units, many people, The counter that goes negative, One row, one queue, Counting in one place, selling in another, Reservations nobody says have ended, and The crowd before the database.

How long is Flash sale and what level is it?

It takes about 16 minutes to read and is rated Senior level.

Now design it yourself

Run this case as an interview in the System Design school: you make the decisions, the tutor challenges them and you see how your design scores.