Question Breakdowns

Online Auction

A worked system design: run live auctions with concurrent bids, a strictly-increasing price, real-time updates to watchers, and a reliable close. Contention on the current bid and the ending race.


An online auction lets many people bid on an item, shows the current high bid live, and declares a winner when time runs out. It's a compact but sharp design because it combines two hard things: contention on a single hot value (the current highest bid, which many bidders race to beat) and a correct, timely close (deciding the winner exactly at the deadline, fairly). It draws on Dealing with Contention and Real-time Updates.

1. Requirements

Functional:

  • Place a bid on an item; a bid is valid only if it exceeds the current high bid (by a minimum increment).
  • Watchers see the current high bid update live.
  • At the end time, the highest bid wins; no bids accepted after.

Non-functional:

  • Correct under concurrency — the price must be strictly increasing; no two bids "both win."
  • Real-time — watchers see new highs within moments.
  • Fair close — the deadline is authoritative; late bids are rejected cleanly.
  • Durable — bids and the outcome must never be lost (money/goods at stake).

2. The contention: beating the high bid

The hot spot is the item's current highest bid — on a popular item, many bidders try to beat it at once. A bid is valid only if it's higher than the current max, so placing a bid is a read-check-write that must be atomic, or two bidders reading the same "current high" could both think they won. This is textbook contention:

  • Conditional update (optimistic): UPDATE item SET high_bid=?, high_bidder=? WHERE id=? AND high_bid < ?. If it updates 0 rows, someone already bid higher — reject and tell the client the new price. The database's atomicity guarantees exactly one winner per round.
  • Per-item serialization: route all bids for one item through a single owner/lock so they're applied in order.

Append every bid attempt to a durable bid log (even losers) for auditability; the item row holds the current winner.

bid → atomic: if bid > current_high then set current_high = bid else reject
    → append to bid history (durable)
    → broadcast new high to watchers

3. Real-time updates to watchers

Everyone watching an item needs the new high bid immediately. Push it over a real-time channel (WebSocket/SSE): when a bid wins, publish the new high to all watchers of that item (a Redis pub/sub channel per item fans it out across servers). Watchers vastly outnumber bidders, so this is a fan-out-to-many broadcast.

4. The close: the ending race

Deciding the winner at the deadline is subtler than it looks:

  • The deadline is server-authoritative. Reject any bid whose server-receipt time is past the end — never trust client clocks. A bid arriving a millisecond late is cleanly rejected, not argued over.
  • Closing the auction is a scheduled action: at end time, mark the item closed (no more bids accepted) and finalize the current high bidder as the winner. A job scheduler or a durable timer (e.g. Temporal) fires the close reliably even across restarts.
  • Boundary correctness: a bid in flight at the deadline must be resolved deterministically — compare its server timestamp to the end; the atomic update either lands before close or is rejected after.

5. Deep dives

  • Anti-snipe extension: some auctions extend the end by a few minutes if a bid lands in the final seconds — just a rule applied at bid time that pushes the scheduled close.
  • Hot item scaling: a blockbuster item funnels all bids through one row/owner; that single-item throughput is the ceiling. Keep the critical section tiny (one conditional update) so it's fast; watchers scale separately via pub/sub.
  • Payment on win: finalizing hands off to a payment flow; hold/charge the winner, with compensation if it fails.
  • Proxy/auto bids: "bid up to X automatically" is resolved server-side against incoming bids.

What to emphasise

Name the contention on the high bid and the authoritative close:

"The hot spot is the item's current high bid, which many bidders race to beat, so placing a bid is an atomic conditional update — set the high bid only if mine exceeds the current one — which guarantees exactly one winner per round and a strictly increasing price; losers are rejected with the new price and every attempt is logged durably. New highs broadcast to watchers via per-item pub/sub over WebSockets, and watchers scale independently of bidders. The close is server-authoritative: the deadline is judged by server receipt time, and a durable scheduled timer finalizes the winner reliably even across restarts, with anti-snipe handled as a rule that extends the scheduled close."


Next up: Job Scheduler — running tasks reliably at a future time.