0b26aa5e

By: Tom Sydney Kerckhove <syd@cs-syd.eu>

Keep the host alive while it has workers to lose

A host that finds it can no longer fork used to exit, and every worker it had
forked dies with it. That threw away warm workers part-way through their
attributes to report a condition that only costs the run its next fork: each
of those attributes then had to be evaluated again, on a worker that had to
load the flake for itself first, and an attribute unlucky enough to lose a
second worker is reported as an error rather than discovered.

It now says so and idles instead, once it has forked anything, and the
coordinator stops asking it for workers rather than killing it. A host that
never got as far as ready has no workers to lose and is still replaced, which
is what makes a fetched flake cost one extra load rather than one per worker.

Killing the pool at the end of a run goes through the host for the same
reason: its workers die with it, so they need no signal of their own, and a
pid this process never waited for is one it should not be signalling at all.
The host reaps what it forks, so such a pid can already mean another process.

Two smaller things in the same place: a "prime" request whose payload is not
an attribute path is answered rather than thrown (the guard above it only
caught malformed JSON, so a type error escaped and abandoned the run), and the
"exit" request the coordinator never sends is gone.

The new check kills the host mid-run and asserts every output is still
reported. What is not covered is the host bowing out on its own: that happens
when nix starts a thread, which a hermetic test cannot make it do.
GitHub
Time to Start Worker time Duration Time to finish Idle
Config 25s 1s 1s 26s 25s
Eval 27s 9s 9s 37s 1s
Build 31s 10m05s - - 26m24s
Suite 25s 10m16s - - 26m51s

Timeline

Config Eval Build Failed Retried Compressed gap
0s27m20s27m40s28m28m20s28m40s29m29m20s29m40s30m30m20s