Boundaries & anti-patterns: hot reload is not a universal hammer
Knowing "when not to use it" matters as much as knowing "how". Volume 4 closes: every boundary collected into one table, then a real attack sample tests the system's resilience.
Overview
31.1 Intro
Hot reload solves the online update of business code. It does not solve: process-structure changes (endpoints/threading model), the rebuilding of non-script resources, and it doesn't suit high-frequency releases. The predicate is simple — if the change involves only "script content + certificates + same-endpoint config", reload; everything else restarts. Carving this boundary into your ops manual beats memorizing ten details.
31.2 The immutable-items summary
| Change | reload outcome | Right path |
|---|---|---|
engine.workers | FAILED (rejected) | restart the process |
| immutable listener fields (recv_limit etc.) | FAILED (explicit rejection) | restart the process |
| endpoint structure (class/ip/port combos that can't hand off) | FAILED (degradation suggested) | restart; or split into two servers and roll |
| scripts of custom-class services | online reload unsupported | restart (raw resources carry no terminal lease) |
| adding / removing custom servers | unsupported | restart |
| script content / certificates / same-endpoint config | SUCCEEDED | reload (that's exactly its job) |
Note custom's position: it hands connections and resources entirely to the application, so the host has no "when is it safe" signal — hence the honest "unsupported" instead of an unsafe switch. Business that needs hot updates belongs on the http/ws/tcp/udp classes.
31.3 Reload bombs & resilience
drill's attack sample list has one aimed squarely at hot reload: the bad-script reload bomb — cyclically submitting uncompilable scripts (the sample fires 6 in a row), paired with func_test's 20-shot storm case, verifying three resilience points:
The sample's point: the reload surface is an attack surface — the management-route auth (ch. 27) blocks external triggering, while the mechanism itself guarantees even an insider's slip can only buy a clean rejection with bad input.
31.4 The anti-pattern collection
| Anti-pattern | Symptom | Right solution |
|---|---|---|
| Reloading every second (as a deployment system) | compile costs pile up; GC queue grows | a reload is a change, not a release; iterate with dev-environment restarts |
| Stuffing a whole database into Swap | swaps slow down; snapshots bloat | big data lives in db/files (naturally cross-generation); Swap carries light state only |
| Sharing raw pointers across generations "for convenience" | sporadic UAF | hand over values (Swap) or global-singleton resources with explicit lifetimes |
| Using reload to cure "weird memory states" | symptom palliation; the problem returns | fix the cause; reload shouldn't be a magic reset button (even though it often "works") |
| Auto file-triggering in production | editor autosave = accidental deployment | auto-trigger is dev-only; production goes through authenticated management routes |
31.5 Contract
- Boundary: scripts/certificates/same-endpoint config → reload; structure/threads/custom → restart.
- Resilience: bad input = clean rejection + intact old generation + bounded queues.
- Discipline: keep reload frequency and Swap size "human-scale" (minute-level changes, KB-level snapshots).
Common mistakes
- Symptom
- FAILED; Message points at a structural change.
- Cause
- Endpoint changes need listener rebuilds — swapping a listener safely online takes a new port as a transition (dual-server rolling) or a restart. Not a defect; an honest boundary.
- Symptom
- Docs/intuition say it reloads; no path exists.
- Cause
- The custom class keeps connections and resources entirely application-owned — the host cannot judge a safe point. Put hot-updatable business on the four protocol classes; keep custom for the genuinely special.
Exercises
Trigger every change in 31.2's table and record each reload outcome message.
Replicate the reload bomb: 20 bad scripts in a burst with one good script inserted mid-way, all under load.
Design and implement a "port change without downtime" scheme (hint: temporary dual servers + client cutover + cleanup).
Summary
| Point | Conclusion |
|---|---|
| The predicate | scripts/certificates/same-endpoint config → reload; everything else restarts |
| Immutable items | workers, listener fields, endpoint structure, the custom class |
| Resilience | bad input cleanly rejected, old generation intact, queues bounded |
| Discipline | minute-level changes, KB-level snapshots, no auto-triggering in production |
| Volume 4 closes | model→trigger→handover→timeline→GC→boundaries: the hot reload loop is complete |
- xrt book · HTTP server — server resilience from the library's viewpoint (timeouts and attack defense)