Summary
On a Linux remote secondmate host, fm-remote-job-worker.sh supervisors accumulate one per remote operation and never exit. Combined with a hole in the restart limiter, this drove a 24-core WSL2 host to a load average of 295, with 800-1000 concurrent worker processes and ~290 of them reparented to init.
Observed
Host: Ubuntu under WSL2, registered as a remote secondmate, reached over the normal remote transport.
$ cat /proc/loadavg
295.84 285.15 239.60 285/1811 1296283
$ ps -eo comm --no-headers | sort | uniq -c | sort -rn | head -3
819 fm-remote-job-w
101 ps
16 bash
Top-level supervisors (ppid == 1), ages spanning minutes to hours, all still alive:
16673 1 10666 /bin/bash .../bin/fm-remote-job-worker.sh
19895 1 973 /bin/bash .../bin/fm-remote-job-worker.sh
27863 1 1664 /bin/bash .../bin/fm-remote-job-worker.sh
32945 1 496 /bin/bash .../bin/fm-remote-job-worker.sh
35221 1 1207 /bin/bash .../bin/fm-remote-job-worker.sh
No systemd unit and no cron entry exist for these; they are started on demand by remote operations.
No single process was CPU-dominant. The load was entirely the aggregate of hundreds of short-lived workers churning.
Mechanism
1. The supervisor has no singleton guard.
worker_acquire_lock is called exactly once, at line 687, inside main(). main() runs for the --serve child and for the non-Linux path. The Linux supervisor entry point does not call it:
'')
if [ "$(fm_remote_job_platform)" = linux ]; then worker_supervise_linux; else main; fi
;;
worker_supervise_linux() acquires no lock of its own, so WORKER_LOCK serialises workers, not supervisors. Every remote operation that starts a bare worker therefore adds another permanent supervisor, and none of them can observe each other.
2. The restart limiter resets on a barely-healthy child.
if [ $((SECONDS - started)) -ge "$FM_REMOTE_JOB_SUPERVISOR_HEALTHY_SECONDS" ]; then
failures=0
sleep 0.1
continue
fi
FM_REMOTE_JOB_SUPERVISOR_HEALTHY_SECONDS defaults to 10. A child that survives just past ten seconds and then exits resets failures to 0 and is restarted after 0.1s. FM_REMOTE_JOB_SUPERVISOR_MAX_RESTARTS (default 20) counts only consecutive sub-threshold failures, so it never fires on this path. One supervisor in that state restarts roughly ten times per second indefinitely; N accumulated supervisors multiply it.
The header comment shows runaway restarts were anticipated. The guard just does not cover a child that dies immediately after crossing the healthy threshold.
Impact
The affected host is a GPU machine intended for ML work. At load 295 it was effectively unusable for its actual purpose, and the secondmate's own status became unreadable from the parent home.
Clearing the processes dropped runnable tasks from ~290/1811 to 1/652 immediately, and the one-minute load average from 295 to 11 within a few minutes. The count then climbed again from 26 to 61 as further remote operations were performed, consistent with the per-operation accumulation above.
Suggested fix
- Give the supervisor its own lock, distinct from the worker lock, so a second supervisor on the same account home refuses to start rather than coexisting.
- Do not reset
failures to zero on a bare threshold crossing, or require a longer healthy interval before resetting, so a child that dies just past the threshold cannot sustain a restart loop the maximum-restart guard never observes.
Possibly related, though a different failure mode: #2772 (remote job worker can swallow TERM after losing ownership).
Workaround
pkill -f "fm-remote-job-worke[r].sh"
Safe in the sense that it does not affect the secondmate agent itself; the next remote operation starts a fresh supervisor.
Summary
On a Linux remote secondmate host,
fm-remote-job-worker.shsupervisors accumulate one per remote operation and never exit. Combined with a hole in the restart limiter, this drove a 24-core WSL2 host to a load average of 295, with 800-1000 concurrent worker processes and ~290 of them reparented to init.Observed
Host: Ubuntu under WSL2, registered as a remote secondmate, reached over the normal remote transport.
Top-level supervisors (
ppid == 1), ages spanning minutes to hours, all still alive:No systemd unit and no cron entry exist for these; they are started on demand by remote operations.
No single process was CPU-dominant. The load was entirely the aggregate of hundreds of short-lived workers churning.
Mechanism
1. The supervisor has no singleton guard.
worker_acquire_lockis called exactly once, at line 687, insidemain().main()runs for the--servechild and for the non-Linux path. The Linux supervisor entry point does not call it:worker_supervise_linux()acquires no lock of its own, soWORKER_LOCKserialises workers, not supervisors. Every remote operation that starts a bare worker therefore adds another permanent supervisor, and none of them can observe each other.2. The restart limiter resets on a barely-healthy child.
FM_REMOTE_JOB_SUPERVISOR_HEALTHY_SECONDSdefaults to 10. A child that survives just past ten seconds and then exits resetsfailuresto 0 and is restarted after 0.1s.FM_REMOTE_JOB_SUPERVISOR_MAX_RESTARTS(default 20) counts only consecutive sub-threshold failures, so it never fires on this path. One supervisor in that state restarts roughly ten times per second indefinitely; N accumulated supervisors multiply it.The header comment shows runaway restarts were anticipated. The guard just does not cover a child that dies immediately after crossing the healthy threshold.
Impact
The affected host is a GPU machine intended for ML work. At load 295 it was effectively unusable for its actual purpose, and the secondmate's own status became unreadable from the parent home.
Clearing the processes dropped runnable tasks from ~290/1811 to 1/652 immediately, and the one-minute load average from 295 to 11 within a few minutes. The count then climbed again from 26 to 61 as further remote operations were performed, consistent with the per-operation accumulation above.
Suggested fix
failuresto zero on a bare threshold crossing, or require a longer healthy interval before resetting, so a child that dies just past the threshold cannot sustain a restart loop the maximum-restart guard never observes.Possibly related, though a different failure mode: #2772 (remote job worker can swallow TERM after losing ownership).
Workaround
pkill -f "fm-remote-job-worke[r].sh"Safe in the sense that it does not affect the secondmate agent itself; the next remote operation starts a fresh supervisor.