CB-559: Features — re-read the config without a restart
+37
@@ -28,6 +28,7 @@ six weeks, and the table alone will not carry it.
|
||||
| [Role pools decide the backend](#role-pools-decide-the-backend) | `fleet.developers:` etc. | CB-557 | `member/CompositePeerLauncher` |
|
||||
| [Tab labels name the role](#tab-labels-name-the-role) | `fleet.tabLabel:` | CB-557 | `member/HerdrPeerLauncher` |
|
||||
| [Launch a lead when none is live](#launch-a-lead-when-none-is-live) | `fleet.leaders.<n>.profile` + `instances` | CB-558 | `lead/LeadLauncher` |
|
||||
| [Re-read the config without a restart](#re-read-the-config-without-a-restart) | `configReload.enabled: true` | CB-559 | `config/ConfigRef` |
|
||||
| [Leads talk to each other](#leads-talk-to-each-other) | (always on, two leads) | CB-532 | `auth/Principal` |
|
||||
| [A lead can be delivered to](#a-lead-can-be-delivered-to) | automatic | CB-534 | `Bridged.deliverableTo` |
|
||||
| [Leads are visible in bridge_list](#leads-are-visible-in-bridge_list) | automatic | CB-535 | `mcp/BridgeMcp.listFleet` |
|
||||
@@ -682,6 +683,42 @@ placed in one would never be found again and would be relaunched on every boot.
|
||||
|
||||
---
|
||||
|
||||
## Re-read the config without a restart
|
||||
|
||||
**What.** `bridged` watches `bridged.yaml`'s modified time and re-reads the file when it changes.
|
||||
Consumers read the live config at the point of use, so a change reaches the next spawn without
|
||||
rebuilding anything.
|
||||
|
||||
**On.** Add `configReload: {enabled: true}`. `intervalSeconds:` sets the poll period (default 10).
|
||||
Absent the block nothing is constructed, so an upgraded daemon behaves exactly as before.
|
||||
|
||||
**Why.** Tuning a fleet meant restarting the daemon, and a restart tears down every lead and worker
|
||||
it owns. Changing one pool's `weight` cost the whole fleet's state, so in practice nobody changed it.
|
||||
|
||||
**Gotcha — three classes of key, and the difference is what already exists at reload time.**
|
||||
|
||||
| Class | Keys | What a reload does |
|
||||
|---|---|---|
|
||||
| **Hot** | `fleet:` (pools + `tabLabel`), `placement:`, an existing profile's `weight` / `maxLoad` / `model` / `tabLabel` | takes effect on the next spawn |
|
||||
| **Deferred** | `lifecycle:`, `leadHeartbeat:`, `guard:`, `worktreeRoot:`, `spawnReadyTimeoutMs` / `spawnReadyPollMs`, **adding or removing** a profile | accepted into the new config, but the startup wiring keeps the old value; logged by name |
|
||||
| **Cold** | `bind:`, `herdrSocket:`, `broker:`, `auth:` | **refuses the whole reload** |
|
||||
|
||||
A changed cold key refuses everything, not just itself. Applying the hot half and warning about the
|
||||
cold half would leave the daemon in a state matching no file on disk — the worst outcome for an
|
||||
operator who is reading the file to work out what the daemon is doing. Refusing keeps one invariant:
|
||||
the live config is always *some* version of the file.
|
||||
|
||||
Adding a profile is deferred, not hot, because a new backend needs its own launcher and launchers are
|
||||
built once at startup. Changing an existing profile's fields is hot, because those are read per spawn.
|
||||
|
||||
A reload that fails to parse, or fails any of the four startup validators, is refused the same way
|
||||
and the running config stays live. A config file being saved is sometimes read mid-write, and
|
||||
degrading a working daemon over a half-written file would be a bad trade. The watcher stamps the
|
||||
modified time **before** it reloads, so a refused file is not retried every tick — the next save
|
||||
earns a fresh attempt.
|
||||
|
||||
---
|
||||
|
||||
## Backfill status
|
||||
|
||||
This page was started after the fact, so it is **not yet complete**. Entries above are written from
|
||||
|
||||
Reference in New Issue
Block a user