Part 5 of 7 · Back-in-stock notifier series ~8 min read

How a reservation gets held

A notice without a hold is just a starting gun for a scramble. This post is about the reservation: how clicking the reserve link locks a single unit for a short window — safely, without ever taking stock below zero — and how a scheduled sweep returns any hold that isn’t used to the next person waiting, so the queue keeps moving and stale requests fall away.

Key takeaways

  • Each notice carries a short-lived, signed reserve link; clicking it holds a single unit for that person for a set window.
  • The hold is a conditional write that decrements the available count and can never take it below zero — so it can’t oversell.
  • The link is single-use and tied to one request and one restock, so it can’t be forwarded, replayed, or shared to jump the queue.
  • An EventBridge Scheduler sweep expires holds that aren’t converted in time, returning the unit to the pool for the next person.
  • The same sweep expires stale requests, so a queue full of people who’ve moved on doesn’t block the ones who still want the item.

A notice without a hold is a starting gun

The notice in Part 4 does its job only if being told actually means getting the thing. If the message just said “it’s back, go and buy it”, then four notices for four chairs would still be a race — the fastest tapper wins, being first in the queue counts for nothing, and if two people reach checkout with the last chair in the same few seconds the shop oversells. The reserve link is what turns the notice from a starting gun into a genuine reservation. It carries a signed token unique to one recipient and one restock, and clicking it does one thing: it holds a single unit for that person for a short window — long enough to get through checkout, short enough that the queue keeps moving.

The link lands on its own Lambda Function URL — the third public surface, separate from capture and the inventory webhook, because it’s a different job with a different shape: a customer clicking a link in a text and expecting to end up at checkout. The function validates the token’s signature (so a guessed or edited link is rejected), checks it hasn’t already been used or expired, and only then attempts the hold. Everything about this step is built around one guarantee: the shop can promise a held unit to whoever clicks, without ever promising the same unit twice.

The hold that cannot oversell

The hold itself is a single conditional write, and it’s the linchpin of the never-oversell promise. The restock record for that SKU carries a count of units still available to hold. When a reserve link is clicked, the function decrements that count with a condition that it stays at or above zero, and writes a reservation row keyed to the token with an expiry timestamp a few minutes out. If the count is already zero — every unit in this restock is spoken for — the condition fails, the hold is refused, and the shopper is shown an honest “just gone, we’ll keep your place” rather than a false promise. Because the decrement is atomic, two people clicking their links in the same instant can never both take the last unit: DynamoDB serialises the two writes, one succeeds, one sees zero and is refused. There is no window in which the shop believes it has stock it doesn’t.

A successful hold writes a reservation and hands the shopper to the store’s checkout with the item reserved — a real cart, held under their name. The reservation row records who holds it, for which restock, and when it expires. That expiry is the important half of the design: a hold is not a sale. Someone can click the link, glance at the price, and wander off, and if a held unit could sit reserved forever, the queue behind them would be stuck — a chair reserved for a person who’s never coming back is exactly as useless as a chair sold to a bot. So every hold has a clock on it, and something has to watch that clock.

Holding and expiring a reservation: reserve-link click holds a unit atomically; a scheduled sweep releases unclaimed holds to the next in line On the upper left, an external box “Shopper clicks reserve link” sends an arrow into a box “Reserve function” on its own Function URL, inside a dotted AWS account container. The reserve function validates the signed single-use token, then attempts a hold: a conditional write to a DynamoDB restocks table that decrements the units-available count only while it stays at or above zero. If the write succeeds, an arrow goes to a box “Reservation held” that writes a DynamoDB reservations row with an expiry timestamp, and on to a box “Store checkout” with the unit reserved. If the count is already zero, an arrow goes to a small “Just gone, keep place” box. On the lower left, a separate box “EventBridge Scheduler, every few minutes” drives a box “Expiry sweep Lambda”. The sweep queries the reservations table for holds past their expiry that were never converted; for each, it returns the unit — incrementing the units-available count back up on the restocks table — marks the reservation expired, and, if units are now free and people are still waiting, enqueues a top-up notify batch to the SQS queue so the next person in line is told. The same sweep also expires stale requests on the requests table. A note reads: a hold can never take stock below zero, and an unclaimed hold returns to the next person in the queue, never to a latecomer. Shopper clicks reserve link AWS account Reserve function token check, atomic hold DynamoDB restocks units-- if ≥ 0 Just gone, keep place zero Reservation held row + expiry_ts held Store checkout unit reserved EventBridge every few minutes Expiry sweep unclaimed holds, stale requests DynamoDB reservations past expiry, unconverted query Return unit: units++ mark expired SQS → notify next in line if units free A hold can never take stock below zero, and an unclaimed hold returns to the next person in the queue — never to a latecomer.
Fig 5. Holding and expiring a reservation. A reserve-link click holds one unit with a conditional decrement that can’t go below zero, then sends the shopper to checkout. A scheduled sweep returns any hold not converted in time, tops the units back up, and offers the freed unit to the next person in line — and clears stale requests as it goes.

The sweep that keeps the line moving

Watching a clock across thousands of holds is a job for something that runs on a schedule, not a trigger — the thing that needs acting on is an event that didn’t happen: a checkout that never completed. That’s the expiry sweep, driven by EventBridge Scheduler on a short cadence (every few minutes). Each run queries the reservations table for holds that are past their expiry and were never converted to a sale. For each one, it does the mirror image of the hold: it returns the unit by incrementing the available count back up on the restock record, and marks the reservation expired so it’s never processed twice. The increment is safe to run repeatedly because the expired marker makes it idempotent — a hold is returned exactly once, however many times the sweep runs.

Returning the unit is only half of it; the point is to give it to the next person in line, not to whoever happens to click a stale link. So when the sweep frees a unit and finds people still waiting on that SKU, it enqueues a small top-up notify batch — the same job Part 4 processes — for the number of units just freed. Marcus, fifth in the queue, is told only now, because a unit has genuinely become available for him and the restock’s cap has room again. The queue always advances by exactly the number of holds that lapsed, in order, and a latecomer who was never on the list is never slipped in ahead of the people who waited. The same sweep also does a quieter housekeeping pass: requests that have sat on a queue past their time-to-live — someone who asked months ago and clearly moved on — are expired off the list, so a restock isn’t spent messaging people who no longer care while the genuinely keen wait behind them.

Design rules that shaped the reservation

  • A notice buys a hold, not a race. The reserve link holds a single unit for the recipient for a short, fixed window.
  • The decrement can’t go below zero. A conditional write makes overselling impossible even when two links are clicked at once.
  • One link, one use. The token is signed, single-use, and tied to one request and one restock — it can’t be shared or replayed.
  • A hold is not a sale. Every hold has an expiry, because a unit reserved forever blocks the whole queue behind it.
  • Freed units go to the next in line. The sweep returns a lapsed hold and tops up a notice to the next person, never a latecomer.
  • Stale requests fall away. Time-to-live clears people who’ve moved on, so a restock isn’t wasted on a queue full of ghosts.
All posts