fix: clean up Xvfb display after browser process crash - #321
Conversation
The kill() method only terminated Xvfb if exitCode was null and the process was not yet killed. When the browser process crashes (SIGSEGV), exitCode is null but the process is already gone — the original check passed, but the Xvfb process was sometimes left orphaned. Fix: always attempt kill() when the process reference exists, regardless of exit state. Wrap in try/catch for the race where the process exits between the check and the kill call. Null out the process reference after cleanup to prevent double-kill. Discovered while running concurrent Camoufox instances with headless=virtual. After browser crashes, stale Xvfb displays accumulated on the host.
|
Thank you for your contribution to this project @dyiapanis.
const p = spawn("sh", ["-c", "kill -SEGV $$"]);
p.on("exit", () => setTimeout(() =>
console.log(p.exitCode, p.signalCode, p.killed, p.kill()), 50));
// null SIGSEGV false false
Cheers! |
Per review feedback, the original kill() changes were dead code: - kill() sets proc=null but get() reads proc.exitCode after calling kill() — TypeError instead of CannotExecuteXvfb - The try/catch was unreachable since kill() returns false without throwing - The real leak: Xvfb is spawned detached:true, and kill() is only called from the browser.close() override. When the browser process crashes (SIGSEGV), browser.close() is never called and Xvfb leaks. Fix: revert virtdisplay.ts kill() to original. Move the fix to syncAttachVD in utils.ts — register 'disconnected' and 'close' event handlers on the browser so Xvfb is killed when the connection drops or the process dies, not just on explicit close(). Idempotent guard prevents double-kill.
|
Thanks for the review — you're right on all counts. The original 1. 2. Unreachable try/catch — Reverted. As you noted, 3. The actual leak — This was the real fix. Xvfb is spawned |
293cc31 to
088bfa9
Compare
|
Hi @barjin — following up on this one as well. Your review points were addressed in |
The kill() method only terminated Xvfb if exitCode was null and the process was not yet killed. When the browser process crashes (SIGSEGV), exitCode is null but the process is already gone — the original check passed, but the Xvfb process was sometimes left orphaned.
Fix: always attempt kill() when the process reference exists, regardless of exit state. Wrap in try/catch for the race where the process exits between the check and the kill call. Null out the process reference after cleanup to prevent double-kill.
Discovered while running concurrent Camoufox instances with headless=virtual. After browser crashes, stale Xvfb displays accumulated on the host.