fix: stop sandbox export children reliably on termination - #10891
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
🟢 Approval recommended
The changes directly address the described subprocess-ownership race and add focused tests that exercise the new termination and cleanup behavior.
Pull request overview
This PR fixes a race during sandboxed exports where receiving a termination signal (e.g., SIGTERM) while a subprocess is being spawned could interrupt ownership/cleanup and leave child processes running. It shifts export termination handling from “raise immediately in the signal handler” to “cancel the active export task and raise on scope exit,” ensuring the subprocess is fully owned and can be reliably reaped.
Changes:
- Update export termination handling to queue task cancellation and preserve the first received termination signal until cleanup completes.
- Harden
run_commandpipe-reader startup so partial reader setup failures still trigger subprocess cleanup and pipe draining. - Add targeted tests covering pipe-reader setup failure, termination at completion, termination during process creation, and repeated termination during cleanup.
File summaries
| File | Description |
|---|---|
| tests/_environments/test_process.py | Adds a regression test ensuring reader-start failures still trigger subprocess cleanup and drain any started readers. |
| tests/_cli/test_export_subprocess.py | Adds deterministic termination-race tests (completion-time signals, repeated termination, and interruption during Popen creation). |
| marimo/_environments/process.py | Tracks created pipe-reader futures so cleanup can drain whatever successfully started, even if later setup fails. |
| marimo/_cli/export/_common.py | Implements export termination via queued task cancellation + deferred SystemExit, preserving signal code and preventing cancellation leakage after scope exit. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The SIGTERM race is fixed by deferring termination to task cancellation, so Popen can return before cleanup takes ownership of its child. Leave pipe-reader startup failures to a separate change. Keep the signal regressions and existing CLI cancellation coverage.
This pull request was authored by a coding agent.
📝 Summary
Closes MO-7679
SIGTERM during sandbox export startup could interrupt
Popenafter the child started but before the caller received its handle, leaving the child running. Queue task cancellation so process creation finishes before cleanup reaps the child.The handler preserves the first termination signal and exit code, allows cleanup to finish through repeated signals, and prevents queued cancellation from affecting work after the export scope closes. Deterministic tests cover interruption during process creation, termination at completion, and repeated termination during cleanup.
Validation:
--experimental-transform-types, mypy reported three errors in unchanged tutorial code, and the sandbox blocked Pixi cache access.📋 Pre-Review Checklist
✅ Merge Checklist