Seat holds and reservation timeouts in a flash sale: an interactive simulator
Selling a limited number of seats, rooms or items means deciding when a buyer gets one. Taking it only at payment lets many buyers race for the same seat and most of them lose after typing in a card. A hold reserves the seat when it is picked, with a time to live so abandoned checkouts give it back. The length of the hold, and whether it is renewed while the buyer is still there, decides how many seats sit idle and how many genuine buyers lose theirs.
The playground runs a flash sale of 500 seats to 3,000 buyers for half an hour under four policies. Change how many buyers abandon checkout.
3,000 buyers rush for 500 seats, and 35% of those who pick a seat abandon checkout part way. Without holds the sale is over in 3.6 min, but a seat is only taken at payment, so 848 buyers fill in their card details and are then told the seat is gone. A 15 minute hold makes payment safe, but every abandoned hold blocks its seat for the rest of the 15 minutes: 2,931 seat-minutes held for people who had left, so buyers see a sell-out that is not real, give up, and 59 seats are still unsold after half an hour. A 4 minute hold frees seats faster but expires under 305 slow, genuine buyers at payment. A 2 minute hold renewed while the buyer is active gets both: no failed payments, a seat is free 2 minutes after its buyer leaves, 506 wasted seat-minutes, and only 1 seat unsold.
- Sold in 10 min
- 500
- Failed at payment
- 848
- Held for leavers
- 0 seat-min
- Unsold at 30 min
- 0
- Sold in 10 min
- 328
- Failed at payment
- 0
- Held for leavers
- 2,931 seat-min
- Unsold at 30 min
- 59
- Sold in 10 min
- 360
- Failed at payment
- 305
- Held for leavers
- 885 seat-min
- Unsold at 30 min
- 11
- Sold in 10 min
- 426
- Failed at payment
- 0
- Held for leavers
- 506 seat-min
- Unsold at 30 min
- 1
What each policy costs
- No holds sells out fastest, in 3.6 minutes here, but only because buyers race each other at payment: 848 of them reach the end of checkout and are told the seat has gone.
- A long hold, 15 minutes, means nobody who reaches payment loses their seat. But about a third of holders walk away, and each of their seats stays blocked until the hold lapses: 2,931 seat-minutes held for people who had left. Buyers see a sell-out that is not real, give up, and 59 seats are still unsold after half an hour.
- A short hold, 4 minutes, gives abandoned seats back sooner but runs out under slow buyers, 305 of whom lose their seat at payment.
- A short hold renewed while the buyer is active gets both: the checkout page extends the hold every few seconds, so genuine buyers keep it as long as they need, and a seat comes back 2 minutes after its buyer leaves. Nobody fails at payment and only 1 seat is unsold.
Holds in SQL
-- take a hold: only if the seat is free, or its hold has lapsed
UPDATE seats
SET held_by = :buyer, held_until = now() + interval '2 minutes'
WHERE seat_id = :seat
AND status = 'available'
AND (held_until IS NULL OR held_until < now());
-- 1 row updated: the seat is yours; 0 rows: someone else has it
-- the checkout page renews while the buyer is active
UPDATE seats SET held_until = now() + interval '2 minutes'
WHERE seat_id = :seat AND held_by = :buyer AND held_until > now();
-- payment succeeded: sell only if the hold is still ours
UPDATE seats SET status = 'sold'
WHERE seat_id = :seat AND held_by = :buyer AND held_until > now();Each step is one conditional update, so two buyers can never hold or buy the same seat. Expired holds need no cleanup job: the condition on held_until treats them as free. For very hot sales, holds often live in Redis with a key per seat and an expiry, and a virtual waiting room admits buyers in batches so the hold store is not hit by everyone at once.
In a system design interview
For ticketing, hotel or flash-sale designs, explain the reservation lifecycle: “Picking a seat takes a hold with a short expiry using a conditional update, so only one buyer can hold it. The checkout page renews the hold while the buyer is active, and payment only succeeds if the hold is still theirs. Expired holds are free by definition, so there is no cleanup race. In front of it, a waiting room limits how many buyers are picking seats at once.” Expect the follow-ups: what happens when payment succeeds after the hold expired, how to show availability without a hot read path, and how to stop bots from holding everything.
Read the guide to bookings and reservations or inventory and flash sales, see optimistic vs pessimistic locking, or watch a strong candidate design a ticketing system.
Questions people ask
What is a reservation hold?
A temporary claim on a limited item, such as a seat or a hotel room, taken when the buyer selects it and released if they do not pay within a time limit. It guarantees the item to that buyer during checkout without selling it yet.
How long should a seat hold last?
Long enough for genuine buyers to finish paying, short enough that abandoned holds do not block inventory. Fixed holds force a trade-off; a short hold renewed while the buyer is active on the checkout page avoids it, because abandoned holds lapse quickly while active ones never do.
What happens without holds?
Many buyers can start checkout for the same seat, and only the first payment succeeds; everyone else learns the seat is gone after entering payment details. During a rush this produces far more failed checkouts than seats.
How do you implement seat holds without double booking?
With an atomic conditional write: an UPDATE that sets the holder only where the seat is available or its hold has expired, or a Redis SET with NX and an expiry. Exactly one buyer succeeds, and payment completes only if the hold is still theirs.
How are expired holds released?
They need no cleanup if every check treats a hold whose expiry has passed as free. A background sweep can still reset expired rows for reporting, but correctness should not depend on it running on time.
What if payment succeeds after the hold expired?
The sale step must check the hold atomically; if it has lapsed and the seat was taken, the payment is voided or refunded and the buyer offered another seat. Authorizing the card first and capturing only after the seat is confirmed avoids charging for nothing.
What is a virtual waiting room?
A queue in front of a high-demand sale that admits buyers in batches, so only as many people pick seats at once as the system and the inventory can handle. It replaces a stampede of refreshes with a fair, first-come order.