Skip to content

process: drain microtasks after emitting 'exit' on natural termination - #34910

Open
robobun wants to merge 6 commits into
mainfrom
farm/b02b6d31/process-exit-microtask-drain
Open

process: drain microtasks after emitting 'exit' on natural termination#34910
robobun wants to merge 6 commits into
mainfrom
farm/b02b6d31/process-exit-microtask-drain

review: thread natural-exit intent explicitly through on_exit()

dea74d5
Select commit
Loading
Failed to load commit list.
Claude / Claude Code Review completed Jul 21, 2026 in 29m 46s

Code review found 2 potential issues

Found 2 candidates, confirmed 2. See review comments for details.

Details

Severity Count
🔴 Important 0
🟡 Nit 2
🟣 Pre-existing 0
Severity File:Line Issue
🟡 Nit src/jsc/bindings/BunProcess.cpp:308-310 Worker: process.exit() inside natural-drain 'exit' listener still drains microtasks
🟡 Nit src/runtime/cli/repl_command.rs:255 REPL eval error path passes natural=true to on_exit()

Annotations

Check warning on line 310 in src/jsc/bindings/BunProcess.cpp

See this annotation in the file changed.

@claude claude / Claude Code Review

Worker: process.exit() inside natural-drain 'exit' listener still drains microtasks

Sibling to the listener-throws gap above: in a **worker** on natural drain, calling `process.exit()` from inside the `'exit'` listener still reaches `vm.drainMicrotasks()`. `WebWorker::shutdown()` nulls `self.vm` (step 1) *before* `vm.on_exit(true)` (step 2), so the re-entrant `process.exit()` → `worker.exit()` reads `self.vm_ptr()` as null and skips `notify_need_termination()` (its own comment documents this) — control returns here with the trap never armed. Node v26 skips the checkpoint on tha

Check warning on line 255 in src/runtime/cli/repl_command.rs

See this annotation in the file changed.

@claude claude / Claude Code Review

REPL eval error path passes natural=true to on_exit()

The `had_error` eval branch (and the interactive-error branch) fall through to `vm.on_exit(true)` here, but `repl.eval_script()` reports the exception via `print_js_error_to()` without going through `uncaught_exception()`, so `unhandled_error_counter` is still 0 and the `natural && unhandled_error_counter == 0` gate passes — microtasks drain after `'exit'` on an error exit. That's inconsistent with the sibling error-path callers this PR updated (line 229 above, `run_command.rs:1710`) and with de