Repository navigation
fix(ci): stop the remote gate before restoring an interrupted ci-remote - #491
Conversation
ci-remote runs make ci on the Pi over ssh without a terminal, and sshd starts that command in a session of its own. A Ctrl-C, a SIGTERM or a dropped connection ends the local ssh, but the Pi run carries on, and the restore trap then reset the Pi checkout underneath it. The next gate could also start while that run was still going. Each gate step (make ci and the drawing comparison) now records its process group on the Pi in .git/ci-remote.pid. The restore first ends that group, TERM then KILL, and only then resets the checkout; if the run cannot be stopped the checkout is left alone and the gate fails. A gate refuses to start while a recorded run is still alive, also with OPENFOLLOW_CI_FORCE. Only the recorded group is signalled, never by name, and a record naming group 0 or 1 is ignored because kill reads those as every process. The test ssh stand-in now runs the remote command in its own session, as sshd does, so the tests reproduce the orphaned run. Fixes #416 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cleanup killed the long step's pid even after it had exited, so a reused pid could take an unrelated process with it. It now kills the step only while it has not reported its stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test polls for the file and reads it at once, so a partly written file could be read as an empty pid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a loaded Pi the dropped-connection case could stop the remote step before it wrote its marker, so the test read the gate as never started. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review roundsRound 1 (full
Round 2
Round 3
Results: After the review ( |
Plan
make ciand during the drawing comparisonSummary
Fixes #416.
ci-remoterunsmake cion the Pi oversshwithout a terminal, and sshd starts that command as a session leader in its own process group. A Ctrl-C, a SIGTERM or a dropped connection ends the localssh, but the Pi run carries on. The restore trap then reset the Pi checkout underneath it, and the next gate could start while it was still running.make ciand the drawing comparison) records its process group in.git/ci-remote.pidon the Pi. sshd makes the remote shell a session leader, so$$is the group id.restorefirst stops that group (TERM, then KILL, up to about 10 s each) and only resets the checkout once it has ended. If the run cannot be stopped (for example, the Pi is unreachable), the checkout is left alone and the gate fails with "could not be stopped, so … was not restored".OPENFOLLOW_CI_FORCE=1. A dead record is removed.killreads those as every process.If the workstation disappears completely, the Pi run finishes on its own. In the meantime it holds off every later gate, and once it has ended the dirty-checkout guard applies as before.
Test plan
tests/test_ci_remote_script.py: the fake ssh forks and runs the command in a new session, like sshdmake ci, drawing comparison}: the step is stopped while the synced tree is still in place (it records this on SIGTERM), then the checkout is restored. An unrelated process on the "Pi" in its own session survives.1,0,01,-1, empty,abcneither block nor stop anythingtests/test_ci_remote_script.py: 37 passed, three runs in a rowmake ci-remoteon the testing PiOPENFOLLOW_CI_FORCE=1("an earlier gate is still running … (process group …)");🤖 Generated with Claude Code