Learning pathsA
Question Breakdowns

Online Auction

An auction needs an authoritative rule for bid acceptance and closing.

Interview scope and guarantees

Create an auction, place bids, display the current leading bid, close at a defined time, and settle the winner. Define proxy bidding, tie rules and anti-sniping extensions before designing. The accepted bid order must be authoritative.

Capacity worksheet

Assume 10,000 active auctions and 100,000 bids/minute: about 1,667 bids/s average. A single celebrity auction can dominate the total. If one serialized bid transaction takes 5 ms, one owner processes roughly 200/s before queueing; that hot-auction limit matters more than aggregate shard count.

Concrete API contract

Contract / pseudocode
POST /auctions/{id}/bids {amount,currency,clientBidId}
GET /auctions/{id}
GET /auctions/{id}/events?after=...
POST /auctions/{id}/close {expectedGeneration}

Data model and access paths

Contract / pseudocode
auctions(id PK,state,closes_at,highest_bid_id,version)
bids(auction_id,sequence,bid_id,bidder_id,amount,accepted_at)
bid_keys(bidder_id,client_bid_id,bid_id)
settlements(auction_id UNIQUE,winner_id,payment_ref,state)

Evolve a solution and explain each change

Three architecture decisions for Online Auction, including the pressure each introduces.
Scroll to inspect the diagram, or open it at full size.

Figure — Three architecture decisions for Online Auction, including the pressure each introduces.

Step 1: Serialize bids

Store accepted bids against an auction’s current price and deadline. Reading the price and then writing can admit invalid concurrent bids.

Step 2: Commit closure

Use the same authority for bids and auction close with server time. A delayed worker can close after the displayed countdown reaches zero.

Step 3: Deliver live views

Stream committed bid/close events and reconcile payment separately. Socket arrival order must not define the winning bid.

Responsibility overview

Connected responsibilities for Online Auction. Trace the authoritative and derived paths separately.
Scroll to inspect the diagram, or open it at full size.

Figure — Connected responsibilities for Online Auction. Trace the authoritative and derived paths separately.

Worked end-to-end scenario

Auction A currently has bid 100. Two bidders submit 110 and 120. The authority validates and commits them in its defined serialization order; an equal or lower amount can be rejected under the increment rule. At close, the transaction establishes the winner from accepted state and prevents later bid admission. A client packet sent before the countdown but received after the authoritative deadline follows the stated admission policy, not its device clock. The winner’s payment is a separate workflow. If collection fails, record the outcome and apply the auction policy rather than retroactively altering the bid history.

Why these access paths matter

Use auction ID as the serialization domain; bids need immutable identity, actor, amount, and accepted order. Index auctions by closure deadline for scheduling, but validate the deadline in bid admission even if the closer is late. Persist close results and notification intents together. Money uses integer minor units or an exact decimal model, not floating point.

Build the baseline first

Online Auction: baseline request paths.
Scroll to inspect the diagram, or open it at full size.
  1. Bidder → auction owner → transactional bid acceptance.
  2. Committed bid → event log → live viewers.
  3. Authoritative close → winner record → settlement.

Evolve the design under load

Online Auction: additional scaling and recovery paths.
Scroll to inspect the diagram, or open it at full size.
  1. Auction-key routing → independent owners.
  2. Hot auction → bounded sequential command queue.
  3. Read projection → regional fanout → viewers.

Defend the hardest decision

Use integer minor currency units and enforce the minimum increment against the committed highest bid. Server receipt or commit order must be chosen as the acceptance rule; client clocks are not authoritative. The close command and bid commands must share an ordering boundary. If anti-sniping extends the auction, persist the new close time in the same bid transaction.

Failure and recovery analysis

A close worker retries after the winning bid was stored but settlement publication failed. The unique settlement row and outbox make recovery safe. If payment fails, apply a documented next-bidder or cancellation policy; do not silently rewrite the accepted auction history. During leader failover, fence the old owner so two leaders cannot accept incompatible winners.

Security and privacy boundary

Authenticate bidders, protect payment data, and detect abusive bidding while keeping the acceptance rules reproducible.

Interview follow-ups with reasoning

Question: Can Redis pub/sub be the bid record?

Show answer and explanation

Answer: No, viewers can miss messages; persist accepted bids first.

Question: How do you handle last-second bursts?

Show answer and explanation

Answer: Admission and queue-delay visibility plus a precise deadline policy.

Question: How do you audit disputes?

Show answer and explanation

Answer: Retain accepted and rejected decision evidence with server ordering.

Operate and verify the design

Bid decision latency, per-auction queue age, close conflicts and unresolved settlement.

Race the final bid and close command under the declared deadline rule and inspect the accepted order.

A second scenario to test transfer

At 12:00:00, a bid handler and a close worker race. The database or auction owner evaluates them under the declared deadline and ordering rule. If the bid is accepted before closure under that rule, it can become the winner. If closure wins, the bid is rejected. The client’s displayed clock and a delayed WebSocket event cannot override the authoritative decision.

Can a bid be accepted solely because the client timestamp is before the displayed close time?

Show answer and explanation

Answer: No. Client clocks and delivery delays are untrusted for the authority decision. Apply the server-defined deadline rule atomically with auction state, and return a stable accepted or rejected result for retries.

Compare alternatives

ChoiceBenefitTrade-off
Single auction ownerClear orderingHot-auction capacity bound
Anti-sniping extensionReduces last-instant bidding effectsMore complex deadline state
Live display cacheFast readsMay lag accepted bids

A design-changing exercise

The close worker is ten seconds late. Are bids during those ten seconds valid?

Show answer and explanation

Answer: Only if that is the explicit product policy. Normally bid admission checks the authoritative deadline independently of when the worker runs.

Design workshop: bids and closure share one order

Choose ascending auctions with a one-dollar minimum increment, no proxy bidding in the baseline, and a server admission rule: a bid is accepted only when its authoritative transaction evaluates before closes_at. Network send time and client clocks do not qualify. Assume bid acknowledgment under 200 ms when admitted; after overload, reject or queue under a declared rule rather than claim every pre-deadline client click wins.

Lock the auction row, verify active state/deadline/current price, persist the command result and accepted bid, and update highest bid in one transaction. Store commands(auction,actor,client_request_id,fingerprint,outcome,bid_id), unique by identity, including rejected decisions when the contract promises stable retries. A retry lookup occurs before repeating deadline checks, so an accepted bid does not become rejected after its response is lost.

sql
BEGIN;
SELECT * FROM auctions WHERE id=:auction FOR UPDATE;
-- First return recorded command result if this identity exists.
-- Verify active, authoritative time < closes_at, and amount >= high+100.
INSERT INTO bids VALUES (:bid,:auction,:actor,:amount_minor,:accepted_at);
UPDATE auctions SET highest_bid_id=:bid,highest_minor=:amount_minor,
                    version=version+1 WHERE id=:auction;
-- Store command result and bid event/outbox in the same transaction.
COMMIT;

The close worker locks the same row and validates the current deadline and generation before freezing the winner. A late worker cannot use an old timer if anti-sniping extended the deadline. Settlement creates a stable winner/order identity and contacts the payment provider outside SQL. Failure to collect invokes a documented resolution policy; it does not silently promote another bidder without audit.

Bid, extension, and old close timer. Bidder to Auction authority: Bid at 11:59:59 under original noon deadline; Auction authority to Auction authority: Optional anti-sniping policy extends to 12:02; generation 8; Close worker to Auction authority: Old timer generation 7 tries closure; Auction authority to Close worker: Reject old generation; current deadline is 12:02; Close worker to Auction authority: At 12:02 freeze winning bid and settlement ID; Auction authority to Payment provider: Charge stable settlement identity outside transaction
Scroll to inspect the diagram, or open it at full size.

Figure — Bid, extension, and old close timer.

If proxy bidding is added, store each bidder's maximum privately. Current price is min(highest maximum, second-highest maximum+increment), bounded below by reserve/start price, with a declared tie order for equal maxima. For maxima A=$150 and B=$120 at $1 increment, A leads at $121, not $150. A later B maximum $160 makes B lead at $151. This extension requires bid-history semantics and confidentiality; a public highest-price field does not implement it.

Close and settlement states. Active -> closed / Locked authority at current deadline / Immutable winning bid or no-sale result; Closed -> payment_pending / Unique settlement/order identity / External attempt queued once; Payment_pending -> unknown / Provider timeout / Query original operation; do not charge a new identity; Unknown -> paid / Verified matching provider outcome / One settlement posting; Unknown -> failed_resolution / Definitive failure under policy / Audited cancellation or explicitly chosen next-bidder workflow
Scroll to inspect the diagram, or open it at full size.

Figure — Close and settlement states.

A live price stream uses committed auction versions and a replay cursor. Display can lag; it never grants acceptance. Hot auctions have a serial capacity bound, so limit in-flight bid decisions and surface overload early. Owner failover restores durable head/version and fences the old epoch before accepting new commands. Monitor command queue wait, deadline rejection, hot-auction transaction time and settlement unknown age separately.

Exercise: Client sends at 11:59:59 but its bid transaction reaches authority at 12:00:01. The deadline is noon. Is it accepted?

Show answer and explanation

Answer: No under this chosen admission rule, unless the authority had already committed an eligible extension. A different receive-before-deadline command-log policy is possible, but must specify the trusted ingress boundary and how queued commands are ordered before closure.

Technical references

Provider idempotency contract example.

PostgreSQL transaction isolation and concurrent updates.

Your study notes