Skip to content

fix(run): await capped browser close on shutdown so Chromium isn't orphaned - #175

Open
JonasJesus42 wants to merge 1 commit into
mainfrom
fix/single-browser-and-shutdown
Open

fix(run): await capped browser close on shutdown so Chromium isn't orphaned#175
JonasJesus42 wants to merge 1 commit into
mainfrom
fix/single-browser-and-shutdown

Conversation

@JonasJesus42

@JonasJesus42 JonasJesus42 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Problem

The shutdown handler in runCommand (SIGINT / SIGTERM / global timeout) did:

if (browser) browser.close().catch(() => undefined); // fire-and-forget
process.exit(130);                                    // kills Node immediately

process.exit is synchronous, so Node died before the async browser.close() ever completed — orphaning the Chromium subprocess on every Ctrl-C or global-timeout shutdown. Under repeated or parallel runs (e.g. inside Conductor) these orphaned browsers accumulate and feed the memory pressure that drives the OS OOM killer to SIGKILL sibling processes (exit 137).

Fix

Make shutdown async and await a capped browser.close() (3s race) before process.exit(130). browser.close() terminates the Chromium subprocess; awaiting it ensures that actually happens, while the cap guarantees a wedged Chromium can't block the exit. Signal and timeout callers invoke it as void shutdown(...). The double-signal fast path (hard exit on 2nd Ctrl-C) is preserved.

Verification

  • bun run check (tsc) passes.
  • Manual: Ctrl-C mid-run, then ps aux | grep -iE "Chromium|headless_shell" — no orphaned processes remain.

Part of the memory-pressure / OOM series (see #173, #174).

🤖 Generated with Claude Code


Summary by cubic

Await a capped browser close (3s max) during shutdown so Chromium isn’t orphaned after SIGINT/SIGTERM/global timeout. This stops zombie browsers from piling up and reduces OOM kills during repeated or parallel runs.

  • Bug Fixes
    • Made shutdown async and await browser.close() with a 3s race to avoid blocking on a wedged Chromium.
    • Updated signal/timeout handlers to call shutdown asynchronously; preserved the fast hard-exit on a second signal.

Written for commit b8cb3f3. Summary will update on new commits.

Review in cubic

…phaned

The SIGINT/SIGTERM/timeout `shutdown` handler fired `browser.close()`
fire-and-forget and then called `process.exit(130)` synchronously — Node
died before the async close completed, orphaning the Chromium subprocess on
every Ctrl-C or global-timeout. Orphaned browsers pile up under repeated/
parallel runs and feed the OOM pressure that SIGKILLs siblings (exit 137).

Make `shutdown` async and await a capped `browser.close()` (3s race) before
exiting. `browser.close()` terminates the subprocess; awaiting it ensures
that actually happens. Signal/timeout callers use `void shutdown(...)`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant