Features: the host no longer idle-sleeps while a member is working (fleetd #355/#374)

Dai Ha
2026-09-07 20:36:32 +07:00
parent 2c7ad8bbc4
commit 474b99fb58
+43
@@ -4669,3 +4669,46 @@ three files exist, and that none is trivially small. Measured on merge: 1420 gre
`ProtectHome=read-only` to `herdr.service` fails 1 test; removing the login shell from
`herdr-inner.sh` fails 1; removing its `stty` fails 1; deleting that file errors 3 and fails the
build rather than passing vacuously.
## The host no longer idle-sleeps while a member is working
`fleetd` now keeps the machine awake for as long as at least one member is live, and lets it sleep
again once the last one goes. On macOS it does this by holding a `caffeinate -i` child process.
**The knob.** A new top-level block, on by default:
```yaml
idleSleepGuard:
enabled: true # set false to turn the guard off
```
It is a **deferred** key: the daemon reads it once at startup, so a change needs a restart. A
reload reports it as such rather than pretending it applied.
**Why it exists.** The Mac that runs this fleet was set to idle-sleep after one minute on battery
(`pmset -g custom` reported `sleep 1`). Over one night the daemon's AMQP link dropped 13 times, and
every drop had a sleep or wake event in `pmset -g log` in the same minute or the minute before. The
broken AMQP link is only the visible symptom. The real cost is a member that freezes mid-turn with
the host — and a long turn with nobody typing is exactly the case that goes idle. Before this, the
fleet needed a human sitting at the keyboard to keep running, which defeats the point of delegating
long work.
**How it knows.** The guard hangs off `SessionManager`'s existing `onAcquire`/`onRelease` hooks and
its `size()`. It does not count members a second way, so it always agrees with the numbers
`fleet_list` reports. Only a real 0→1 or 1→0 crossing touches the OS.
**Gotchas — three, and all of them are by design.**
- **It is macOS-only.** `caffeinate` ships on no other platform, so on Linux — fleet01, for example
— the guard is a clean no-op. It says so once at INFO and never again, so a daemon running for
weeks does not fill its log. fleet01 has the same exposure and does **not** get the fix from this
change; a Linux mechanism (`systemd-inhibit`) is a separate job.
- **`-i` is idle sleep only.** Closing the lid still sleeps the host, and so does an operator asking
for sleep. That is deliberate: the guard stops an unattended host sleeping under a member's turn,
it never overrides the operator. `caffeinate -s`/`-d` would do that and are not used.
- **It fails safe, and silently.** If the mechanism cannot start — binary missing, process table
full — `acquire()` returns null and nothing is ever held. The guard never throws, and never blocks
a spawn, a release or shutdown. So "the guard is enabled" is not proof the host is awake. The
proof is a live `caffeinate` process, or a member that survives an idle night.
fleetd #355 / #374.