Repository navigation
fix(runner): run the runner under tini so orphaned children get reaped - #7915
Conversation
On Kubernetes nothing adds an init process, so tsx is PID 1 and every pi or pi-acp whose parent exits stays a zombie for the life of the pod. Install tini in both runner images and make it the ENTRYPOINT. -s keeps it working under compose's init: true. Entire-Checkpoint: 01M64JG63C6FPQW2N3PWCG2CGB
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Install and configure tini services/runner/docker/Dockerfile.dev, services/runner/docker/Dockerfile.gh |
Both images install tini and set tini -s -- as the entrypoint. The existing CMD instructions remain unchanged. |
Priority:
Estimated code review effort: 2 (Simple) | ~5 minutes
Merge Risk: 
Minimal · up to ae962
-
The runner images retain their existing startup and shutdown behavior while adding zombie-process reaping.
Pre-merge checks: 
5
-
Full details: Docstring Coverage
-
Explanation
No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 0 files. (2 skipped: 2 unsupported.)
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
Railway Preview Environment
Dependent tests finished. Post /preview for manual review. Environment absence verified; retained storage requires separate provider accounting. Post |
Problem
On Kubernetes, runner pods collect zombie (
<defunct>) processes. A runner pod showed six zombies after 29 minutes: threepiand threepi-acp, about two for each local session. The zombies hold no memory. They do take process table slots, and they stay until the pod restarts.The cause is PID 1. The image runs
tsx src/server.ts, sotsxis PID 1. When a process in the chainsandbox-agent→pi-acp→piexits, its children are handed to PID 1. Node only reaps children it started itself, so those processes stay as zombies. Docker compose already avoids this withinit: true(#5557). The Helm chart and the Railway wrapper use the image default, so they never got the fix.Change
Both runner images (
Dockerfile.gh,Dockerfile.dev) install Debian'stinipackage (about 730 KB) and setENTRYPOINT ["tini", "-s", "--"]. The CMD is unchanged, so a composecommand:override still works.tiniforwards SIGTERM to its direct child only. The runner still gets the signal first and drains its turns, as before.-smakestinia subreaper. It still reaps when compose'sinit: truemakes Docker's own init PID 1, and it prints no warning there.This fixes the Helm chart, Railway, and plain
docker runtogether, with no chart change.Tests
On a local build of
Dockerfile.gh, a Node parent startssh -c "sleep 1 & exit 0", andpsruns 3 seconds later:sleep--entrypoint node)nodeZ)tini--init(compose)docker-init, thentinidocker stopon the real runner, with and without--init: the runner logsreceived SIGTERM, draining and cleaning up sandboxesand exits 0.I did not build
Dockerfile.devlocally. Its change is the same two lines.What to QA
After a stage deploy, run a few local sessions. Then check that
kubectl exec <runner-pod> -- ps -eo stat,comm | grep -c '^Z'stays at 0 and that a rollout still drains turns.