The live auction
An auction house wants live bidding in the browser. A rare painting, ten thousand bidders, a countdown timer, and a new highest bid every few seconds. Every bid has to be visible to every participant in real time, and no bid can be lost.
Solution A broadcasts every bid to every connected client. Simple, fair, and correct. The catch is scale. Ten thousand sockets each receiving every bid means the server sends hundreds of millions of frames per auction. Fine for a few hundred bidders, brutal for ten thousand.
Solution B uses room-based targeting. Clients subscribe to the auction room they care about. The server only broadcasts within that room. A bid on painting A never crosses to auction B. You also add backpressure on the socket: if a client is slow to read, you drop old bids and send only the current top bid, because the intermediate values are stale anyway.
async function placeBid(auctionId: string, amount: number, bidder: string) {
const key = 'auction:' + auctionId;
// Optimistic concurrency: WATCH aborts the write if another bid lands first
await redis.watch(key);
const auction = JSON.parse(await redis.get(key));
if (amount <= auction.currentBid) {
await redis.unwatch();
throw new Error('Bid must be higher than ' + auction.currentBid);
}
auction.currentBid = amount;
auction.bidder = bidder;
// Fairness: the server's clock orders bids. Client timestamps are
// untrusted input, so two bids race on arrival order at the server.
auction.timestamp = new Date().toISOString();
// Durability before delivery: persist first, broadcast after the
// write succeeds. A crash mid-broadcast can never lose an accepted bid.
const ok = await redis.multi().set(key, JSON.stringify(auction)).exec();
if (!ok) throw new Error('Another bid won the race, retry');
return auction;
}The no-lost-bids guarantee lives here: every bid is stamped with server time and persisted atomically before anyone hears about it.
function broadcastBid(roomId: string, bid: Bid) {
const room = rooms.get(roomId);
if (!room) return;
for (const client of room) {
if (client.bufferedAmount > 1_000_000) {
// Slow client. Coalesce: only send the most recent bid.
client.latestBid = bid;
continue;
}
client.send(JSON.stringify({ type: 'new_bid', bid }));
}
}Send only the latest bid to slow clients to avoid backpressure.
Quiz: Quiz
Loading practice…