fix(cli): 1.31.1 — reaper no longer blocks the daemon event loop
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

1.31.0 introduced a session reaper that called execFileSync(ps) once
per registered session every 5s. With many sessions registered, the
daemon's event loop stalled for hundreds of ms — long enough that
incoming /v1/version probes from the CLI timed out against a healthy
daemon and the new service-managed warning fired.

Fix:

- getProcessStartTime is now async (execFile + promisify); never
  blocks the event loop
- New getProcessStartTimes(pids) issues one batched ps for all
  survivors instead of N separate forks. Sweep cost is fixed
  regardless of session count.
- registerSession stays sync; start-time capture is fire-and-forget
- reapDead is now async; the setInterval wrapper voids it so a
  rejected sweep cannot crash the daemon

Behavior is otherwise unchanged from 1.31.0: same 5s cadence, same
PID-reuse guard semantics, same broker-WS teardown via the registry
hook. 83/83 tests still green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-04 14:15:48 +01:00
parent b0c1348a0a
commit 15b7920b2a
5 changed files with 167 additions and 43 deletions

View File

@@ -1,5 +1,33 @@
# Changelog
## 1.31.1 (2026-05-04) — hotfix: reaper stops blocking the daemon event loop
1.31.0 shipped a session reaper that called `execFileSync("ps")`
synchronously, once per registered session, every 5 seconds. With ten
or more sessions registered the daemon's event loop stalled for
hundreds of milliseconds at a time — long enough that incoming
`/v1/version` probes from the CLI failed to return within the 2.5 s
budget and the new "service-managed daemon not responding within
8000ms" warning fired against a perfectly healthy daemon.
Fix:
- `getProcessStartTime` is now async (`execFile` + promisify), never
blocks the event loop.
- New `getProcessStartTimes(pids)` issues a single batched `ps -p
<p1>,<p2>,...` for every survivor in one fork — sweep cost is fixed
regardless of session count.
- `registerSession` stays synchronous: the start-time capture runs
fire-and-forget so the IPC route returns instantly. The reaper falls
back to bare liveness for the brief window before the start-time
lands.
- `reapDead` is now async; the setInterval wrapper voids it so a
rejected sweep can never crash the daemon.
Behavior is otherwise unchanged from 1.31.0 — same 5 s cadence, same
PID-reuse guard semantics, same broker-WS teardown via the registry
hook.
## 1.31.0 (2026-05-04) — session autoclean, install-time broker verification, no more spurious cold-path warnings under service management
**Three operability changes targeting users who installed the daemon as a launchd / systemd service.**