A handler reads the shared routing reference once at request start and a new table is published mid-request; what has that handler gained and lost?
answer
- safe and current are different
- one read fixes the view
- consistency bought with staleness
- staleness bounded by request duration
- old versions live while readers hold them
basics
~20 sIt gained a stable snapshot: every decision in that request is taken against one version, with no lock and no risk of routes shifting between two lookups. It lost freshness, acting on a table it already knows may be superseded.
solid answer
~40 sReading the reference once fixes the handler's view for the whole request. Both lookups it makes, and any decision derived from them, come from one internally consistent version, and it achieves that without holding anything and without blocking a publisher. The price is staleness: from the instant a newer table is installed until this request ends, the handler is deciding on old routes. Where you read the shared reference is therefore the real design knob, because it sets the unit of consistency. Read it once per request and the request is consistent but possibly stale; read it before every lookup and you are fresher but two lookups can straddle a publication. The old version also stays alive while any handler still holds it, so several versions coexist in memory.
code
pseudocode · 12 lines// one read: every lookup in the request agrees with every other
function handle(request)
table = currentTable // the consistency unit starts here
primary = table.lookup(request.host)
backup = table.backupFor(primary) // same version as the lookup above
return forward(request, primary, backup)
// re-read per lookup: fresher, but the two lookups can straddle a publication
function handleFresh(request)
primary = currentTable.lookup(request.host)
backup = currentTable.backupFor(primary) // possibly a version that lost `primary`
return forward(request, primary, backup)go deeper
Hold on to the distinction: a snapshot is safe to read but not necessarily the latest. Reading the shared reference again is the only thing that moves a handler forward a version.
Explain why one read per request makes every lookup agree, and what the handler gives up in exchange. Be able to state the staleness window in terms of publication timing and request duration.
Show the operational consequences: several versions pinned in memory by in-flight requests, two concurrent requests legitimately routing differently, and a deliberate choice about where the reference is read.
Set the rule others follow. Decide what the acceptable staleness bound is for this class of data, which decisions may not be taken from a snapshot at all, and how request duration is bounded so version retention stays predictable.
## Two different questions, often confused *Is this value safe to read?* and *is this value current?* are independent. Immutability answers the first completely and says nothing at all about the second. A handler holding a routing snapshot holds a version that cannot change under it; whether that version is the one the operator most recently published is a separate matter, decided entirely by when the handler last read the shared reference. That separation is the whole content of this trade. ## What the single read buys Reading the reference once, at the start of the request, and passing the value down gives the handler: - **internal consistency.** Every lookup in the request comes from one version, so a primary route and its backup, or a route and the policy attached to it, cannot come from different worlds. - **freedom from coordination.** No acquire, no release, no retry, nothing a publisher has to wait for. - **a stable basis for reasoning.** Two lookups an arbitrary distance apart in the code answer as if they happened at the same instant, which is what makes the handler testable against a fixed table. ## What it costs - **Staleness with a bounded window.** From the moment the new table is installed, this handler is working with the old one for the remainder of its request. The bound is the request's own duration, which is usually the reason the bound is acceptable. - **Several versions alive at once.** The old table cannot be reclaimed while a handler still references it, so at any instant the process may hold the current version plus every version still held by an in-flight request. Environments differ in whether that reclamation is automatic once the last holder drops it or has to be arranged explicitly, but the shape is the same: lifetime follows the last reader, not the publication. - **A visible skew.** Two requests running concurrently may route differently because they captured different versions. That is correct behaviour and it still confuses whoever is reading the logs, so it is worth stating in the design. ## Where you read the reference is the knob | Read the reference | Consistency unit | Freshness | Typical fit | |---|---|---|---| | once per request | the whole request | one publication behind, at most one request long | routing, configuration, feature state | | once per operation inside the request | one operation | tighter | long-running requests where each step is independent | | before every lookup | a single lookup | tightest available | lookups with no invariant relating them | Nothing on this table is safer than the others; every row reads a complete version. What changes is the span over which the handler's answers are guaranteed to agree with one another. Pick the span that matches the invariants of the work, then make it explicit in the code by reading the reference exactly once at the top of that span and passing the value down. ## The failure this prevents The bug that motivates the single read is not a crash. A handler that reaches for the shared reference at each lookup can resolve a primary route from one version, then resolve that route's backup from the next version, in which the primary no longer exists. Each read was safe, each version was coherent, and the pair the handler assembled never existed in either. Nothing in the immutability argument protects against that, because the protection an immutable value gives ends at the edges of that value. ## How to defend the trade in review 1. **Name the staleness bound out loud:** worst case is one publication period plus one request duration. If that is not acceptable for a particular decision, that decision needs its own mechanism, not a different table. 2. **Say what holds the old versions alive** and roughly how many can be in flight, so memory is a calculated figure rather than a surprise. 3. **Show where the reference is read** and why that point is the boundary of the consistency you actually need. The summary an interviewer wants: the handler traded currency for a consistent, uncoordinated view, and the place it reads the shared reference is where it sets that exchange rate.
- How stale can a handler's view get?As stale as the time since it last read the shared reference. With a single read at request start, the worst case is the interval between the publication and that read, plus the request's own duration. It never grows unboundedly, because the next request reads the reference again and starts from whatever is current then.
- What keeps an older table alive after a newer one has been installed?The handlers still holding it. A version stays reachable until the last reference to it is dropped, so the process can hold the current version plus one per in-flight request that captured an earlier one. Long-running requests therefore pin memory, which is a reason to bound request duration rather than to abandon the design.
- Two concurrent requests route the same host differently. Is that a bug?Not by itself. They captured different versions across a publication, and each decided coherently against the version it held. It becomes a bug only if some invariant requires the two requests to agree, in which case the agreement has to come from something other than a snapshot each of them reads independently.
saying these in an interview costs you the question
- Assumes every reader sees the newest table the instant it is published
- Re-reads the shared reference per lookup and still calls the request consistent
- Thinks a handler holding an old version corrupts or delays the new one
- Ignores that several versions stay in memory while readers hold them
- Treats staleness as a defect rather than the price of not blocking
- Believes the held value is updated in place when a publication happens