Replace systemd and start-up.sh with process-compose - #318
Conversation
Supervise Jupyter and the code-interpreter server with process-compose in both the E2B sandbox and the Docker image, so the two paths can no longer diverge. Restart policies, ordering and the ExecStartPre health check gate map over directly; PartOf=jupyter.service becomes a readiness probe that compares Jupyter's reported start time against the one recorded at gate time, which is sticky and so cannot be missed the way a liveness check can. Jupyter writes its log file directly rather than through process-compose. Kernels inherit its stdout and stderr and outlive it, and process-compose waits for those descriptors to close before acting on the exit, so letting it capture them left a killed Jupyter unrestarted while any kernel ran. The restart tests never exercised any of this: `pgrep -f 'jupyter server'` matched the shell running it, so the kill only ever hit itself and the catch swallowed the error. They now use a bracketed pkill that fails on no match, and judge recovery by running code, since the old server answers /health for several seconds while holding dead kernel handles. Co-Authored-By: Claude <noreply@anthropic.com>
PR SummaryHigh Risk Overview Jupyter logs go directly to Removes systemd units, Reviewed by Cursor Bugbot for commit 469b439. Bugbot is set up for automated code reviews on this repo. Configure here. |
Jupyter and the code-interpreter server are now supervised by process-compose in both the E2B sandbox and the Docker image, so the two paths can no longer diverge; restart policies, ordering and the
ExecStartPrehealth check gate map over directly, whilePartOf=jupyter.servicebecomes a readiness probe comparing Jupyter's reported start time against the one recorded at gate time (a sticky signal, unlike a liveness check which loses the race — Jupyter recovers in ~1s). Jupyter writes its log file directly rather than through process-compose, because kernels inherit its stdout/stderr and outlive it, and process-compose waits for those descriptors to close before acting on the exit — capturing them left a killed Jupyter unrestarted while any kernel ran, silently breaking the OOM recovery the systemd setup existed for. The restart tests never exercised any of this:pgrep -f 'jupyter server'matched the shell running it, so the kill only ever hit itself and thecatchswallowed the error; they now use a bracketedpkillthat fails on no match and judge recovery by running code, since the old server answers/healthfor several seconds while holding dead kernel handles. Thedebug=Truesystemd drop-in is gone (logs are always captured now) anddebug_logs.py/README point at the new log files.Verified against a clean Docker build: boot to working execution in 3s, 20s steady state with zero restarts or probe failures, kill Jupyter with kernels alive → both restart and execution works in 7s, kill code-interpreter → only it restarts in 3s. One trade-off:
/var/log/jupyter.logis no longer rotated, since process-compose can't capture it; Jupyter can rotate its own log viaApplication.logging_config, but that sends startup stderr to/dev/null, losing exactly whatmake debug-templateexists to show.🤖 Generated with Claude Code