The generation lifecycle: the complete timeline of the reload instant
What happens when a hot reload is submitted while 10 concurrent requests are in flight? This chapter draws the whole process from compile to the old generation's burial — the standard answer to ch. 3's challenge.
Overview
29.1 Intro
The hardest part of hot reload isn't "swapping the code" but the instant of the swap: is the port still listening? Who owns in-flight requests? How do two generations coexist — and part? The answers hide in two mechanisms: the listener slot (the source of port stability) and the lease (the source of request attribution). String them along a timeline, and you have this chapter.
29.2 The end-to-end timeline
- t3 is the dividing line: before it everything may fail or cancel; after it only forward is possible (new intents queue up)
- t5's switch is atomic: a connection begins either from the old generation or the new — there is no "half a new generation"
- Every request sees exactly one generation throughout — the core invariant of dual generations, and the entire secret of "edit code without dropping connections"
29.3 Listener slots & handoff
Handoff is what makes "old and new generations on the same port" possible: the listening socket never closes and reopens — from outside, the service is never unreachable for even a millisecond. TLS endpoints behave the same, and the ClientHello's identity selection (SNI) is bound to the same Accept by the cookie mechanism — handshakes never straddle generations.
29.4 Lease holders
| Holder | Acquired | Returned |
|---|---|---|
| HTTP request | after Accept, via the slot's current generation | response complete + body drained (keep-alive holds until the connection ends or the next request re-attributes) |
| WS / TCP connection | connection established | connection terminal (Close/Abort) |
| UDP datagram | once per datagram | returned when processing completes |
| Timer | bound to its generation at creation | fired, or invalidated by the swap |
| TAKEOVER connection | at takeover | when you finally Close (ch. 25's contract) |
So "when does the old generation die" is decided entirely by leases: HTTP returns to zero within seconds after a swap (with keep-alive idle timeouts); long-connection services can drag on — precisely the mechanism behind the lifecycle test asserting "old keep-alive connections keep the old script, terminal reclamation without timeout".
29.5 Contract
- Attribution: every request sees exactly one generation; the swap switches atomically with zero port flicker.
- Parallelism: during coexistence the generations don't disturb each other; the old generation accepts no new requests.
- Reclamation: the old generation's death time = the last lease's return time (GC details in ch. 30).
Common mistakes
- Symptom
- Expectations like "traffic split half old, half new" after a reload come to nothing.
- Cause
- After the slot switches its pointer, all new connections enter the new generation — the old is out-only. For canary traffic use vhosts / dual servers, not swap ratios.
- Symptom
- After submitting a reload, no new gen number appears; assumed ineffective.
- Cause
- The gen number lives on the
script loadedline; if the content fingerprint is identical (Revision unchanged) or the target is wrong (verify via the result.Target field), no swap ever happened. Trust xsReloadQuery's terminal, not guessed logs.
Exercises
Draw 29.2's timeline with the book closed, marking t3 (the irreversible point) and t5 (the pointer switch).
With a long connection (WS) plus three rapid reloads, confirm three pieces of evidence that one connection is served by the same generation throughout (behavior marker, log gen, Swap data).
Mirroring reload_matrix: a hammer thread hits /ready every 10ms while you swap 5 times; count failures.
Summary
| Point | Conclusion |
|---|---|
| Timeline skeleton | snapshot→compile→Swap→irreversible point→Init→pointer switch→leases to zero→GC |
| Port stability | slots hold sockets and switch pData — handoff with zero flicker |
| Dual generations | old is out-only; every request sees one generation |
| Lease table | requests/connections/datagrams/timers/takeovers each have acquisition and return points |
- xrt reference · atomic — the memory ordering behind slot pointer switches and lease counting
- xrt reference · tcp_server — sharing and reuse patterns for listening sockets