The reload model: desired-state reconciliation
Hot reload is not a function — it's a coordination system. This chapter builds its mental model; once "intents" and "snapshots" click, the next five chapters just add detail to this model.
Overview
26.1 Intro
The naive hot-reload design is "call a function, swap the code synchronously" — it goes bankrupt instantly in a concurrent world: at call time 50 requests still run on the old code; swap what, and how? XServer's answer is modeling it as desired-state reconciliation: what you submit is not "change it now" but "I want the service to become this content"; a coordinator (a dedicated reload control thread) serially compares, compiles and publishes, recording outcomes as queryable terminal states. This model settles concurrency, failure and duplicate-submission problems natively.
26.2 Desired-state reconciliation
- Submission decoupled from execution: Submit never blocks the calling thread — you can submit a reload from inside a request callback
- Single-threaded coordination: all intents execute serially on one control thread — no "two reloads stepping on each other"
- Auditable outcomes: every intent has a stable ID and a seven-state terminal; a ring of the last 256 results is kept
26.3 Intents & the seven states
Each Submit is an intent. An intent's lifecycle:
latest-wins is easy to underestimate: edit your config five times and submit five times, and only the last one executes — the intermediate states never went live. That's exactly the right semantics both for "edit while thinking" development and "roll back fast" operations.
26.4 Immutable snapshots
When accepting an intent, the coordinator does one crucial thing: freezes the input — the config bytes plus all relevant script sources are snapshotted at that instant, and a content fingerprint (Revision) computed. From then on:
- Within one reconcile (especially xsReloadAllSubmit), every server sees the same input — no "server A on new config, server B on half-new config" tearing
- However the files on disk change during execution, this intent is unaffected — editing files and submitting intents are two actions; after the snapshot it's one complete transaction
- Revision is the audit anchor: two successful reloads with the same Revision = content unchanged (the coordinator can short-circuit on it); logging the Revision sequence traces "which version ever went live"
26.5 Contract
- Submission: Submit is non-blocking and returns a stable ID; 0 = not accepted (e.g. pending full).
- Execution: a single control thread runs serially; after the side-effect zone (publish), new intents can only queue — they cannot cancel the one in flight.
- Input: intents freeze immutable snapshots; Revision is the content fingerprint and audit anchor.
Common mistakes
- Symptom
- Asserting new behavior right after Submit; tests fail randomly.
- Cause
- Submit only means "intent accepted" — the terminal comes from Query. Even the bool wrappers (xsReloadHost etc.) only report acceptance.
xsReloadHost(pHost);
assert(NewBehavior()); /* may not be published yet */XS_ReloadId id = xsReloadHostSubmit(pHost);
/* poll xsReloadQuery to a terminal, then assert */- Symptom
- Service behavior unchanged after editing the devfile.
- Cause
- XServer has no built-in file watcher — editing a file is just editing a file; the snapshot happens when the intent is submitted. For a "save-and-reload" dev experience, build it yourself with xrt file watching + auto-Submit (ch. 27's exercise).
Exercises
Write a management route that submits a reload and queries every 10ms, printing the State sequence.
Fire three intents back to back (each version's route returns a distinct marker) and confirm only the last went live, the first two SUPERSEDED.
Add history lookup to the management route: dump the last N intents' ID/State/Revision/Message from the result ring.
Summary
| Point | Conclusion |
|---|---|
| Model | desired-state reconciliation: submit intents, not synchronous commands |
| Execution | one serial control thread; Submit non-blocking with a stable ID |
| Seven states | ACCEPTED→PREPARING→SUCCEEDED/FAILED/SUPERSEDED/CANCELLED |
| latest-wins | older intents on a server get overwritten; intermediates never go live |
| Snapshots | inputs frozen at acceptance; Revision is the fingerprint and audit anchor |
- xrt reference · queue — the SPSC/MPSC structures under the intent queue and result ring