metric

Oversell Window

also called Projection Lag Exposure, Stale Stock Window

The interval between a reservation becoming true and the read model reflecting it, multiplied by the demand rate - which is the quantity of orders a system can accept for stock it does not have.

flash saleread modelprojection laginventoryconsistency

A sale opens at midnight. By eight seconds in, the inventory read model lags the authoritative reservation store by 40 seconds. By thirty seconds in, the product page still shows stock for an item that sold out at six seconds, and 11,000 orders have been accepted for it.

Nothing crashed. The event pipeline did exactly what it was built to do, at a lag that was irrelevant at normal volume and decisive at sale volume. The oversell window turns that lag into a number you can plan against: lag in seconds multiplied by accepted orders per second is the exposure.

Why it matters

It converts an architectural argument into arithmetic. "The read model is eventually consistent" is a property; "40 seconds of lag at 300 accepted orders a second is 12,000 oversold units" is a business decision that a product owner can accept or refuse.

The mechanism that makes it dangerous is that lag is not bounded by anything. Input rate is set by customers; the projection's output rate is set by consumer throughput. Under a spike the two diverge, and then the feedback loop closes: a page showing stock generates purchase attempts, attempts generate events, and the lag increases the traffic that increases the lag. That is why 8 seconds becomes 40 rather than 9.

The cost is not only refunds. It is cancellation handling, customer-service load, regulatory exposure where advertised availability is a consumer-protection matter, and the operational work of unwinding partially fulfilled orders.

Implementation patterns

  • Reserve synchronously against a single authority per item. An atomic decrement on one row, sharded by item. Nothing downstream may accept an order without a successful reservation; the read model informs, it never authorises.
  • Pre-allocate sale inventory into claim tokens before the sale opens. Convert the stock into a fixed set of claims distributed across shards or edge locations, so a claim succeeds or fails locally. It turns a consistency problem into a counting problem, which is the only shape that holds at hundreds of thousands of operations per second.
  • Display what you can honestly display. "Limited stock", or a queue position, rather than a number that may be 40 seconds old.
  • Degrade automatically on lag. When projection lag crosses a threshold, switch the page to the advisory form. The threshold is a product decision made in advance, not an incident call.
  • Alert on age of the oldest unprocessed event, in seconds, not on queue depth — and on accepted orders minus successful reservations, which should be exactly zero.

Industry example

Alibaba has reported peak order creation of 583,000 per second during Singles' Day in 2020. At that rate, a one-second projection lag is over half a million orders of exposure, which is why extreme flash-sale architectures do not rely on a shared consistent view at all: inventory is pre-allocated into independent claimable units, traffic is isolated so the sale cannot starve the rest of the platform, and the whole path is rehearsed under synthetic load before the date.

The generalisable part is the rehearsal, not the topology. A system that idles at a small fraction of its peak for 364 days cannot be validated by ordinary load testing, and the oversell window is one of the specific quantities a rehearsal exists to measure.

Failure scenarios

  • Orders accepted against a stale read, each one a correct response to a question asked of the wrong system.
  • Lag alerted on queue depth, which stays unremarkable while the age of the oldest event grows.
  • Cancellation storms after the sale, as oversold orders are unwound, generating their own load spike at the worst time.
  • A hot item concentrating the whole exposure, because demand is far more skewed than the partitioning assumed.
  • Compensating logic that double-refunds, because the cancellation path was written during the incident and is not idempotent.

Trade-offs

Synchronous reservation costs a coordination point per item, which caps per-item throughput at what one authoritative counter can do, and makes that counter a hot spot. Pre-allocation costs planning and a reconciliation step, because tokens unclaimed in one shard are stock that appears sold out when it is not — a real and accepted inefficiency.

The alternative, an asynchronous view authorising orders, costs nothing in architecture and charges the whole bill in refunds and trust. The honest comparison is coordination cost against oversell cost, both quantified.

When not to use it

At low rates, one authoritative row with an atomic decrement is correct and sufficient. It handles thousands of operations a second and needs no token pre-allocation, no edge-local claims and no reconciliation. A sale of 200 units to a few thousand customers should use exactly that.

The window is also not worth computing where overselling is acceptable by design — airline and hotel overbooking are deliberate, priced and compensated. There the quantity to manage is the compensation budget, not the lag.

Interview question

Q: Your product page shows live stock from a read model fed by events. The business wants to run a flash sale at 50 times normal order volume. What do you measure beforehand, and what do you change before the date?

What a strong answer covers: measuring projection lag under synthetic load at the planned rate, and multiplying it by the accepted-order rate to state the exposure as a number · moving authorisation to a synchronous reservation against a single authority per item, so the read model becomes advisory · pre-allocating sale inventory into claim tokens if one counter cannot serve the peak · changing the display to an honest form and adding automatic degradation at a pre-agreed lag threshold · the two metrics to watch live — age of the oldest unprocessed event, and accepted orders minus successful reservations · rehearsing the whole path, because a system that peaks once a year cannot be validated by ordinary load testing · and naming when none of this is needed, which is any rate a single atomic counter can absorb.

Quick check

Quiz: How do you express an eventually consistent inventory view as a business number? — Lag in seconds multiplied by accepted orders per second: the quantity of stock you can sell without having it.

Flashcard: What is the one rule separating advisory from authoritative in an event-driven design? — An asynchronously maintained view may inform a user and must never authorise a transaction.