Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bun.js.zig
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ pub const Run = struct {
vm.eventLoop().tickPossiblyForever();
}
} else {
while (vm.isEventLoopAlive()) {
while (!vm.shouldExitProcess()) {
vm.tick();
vm.eventLoop().autoTickActive();
}
Expand All @@ -436,7 +436,7 @@ pub const Run = struct {
vm.tick();
vm.eventLoop().autoTickActive();

while (vm.isEventLoopAlive()) {
while (!vm.shouldExitProcess()) {
vm.tick();
vm.eventLoop().autoTickActive();
}
Expand Down
38 changes: 38 additions & 0 deletions src/bun.js/VirtualMachine.zig
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,44 @@ pub fn isEventLoopAlive(vm: *const VirtualMachine) bool {
vm.event_loop.next_immediate_tasks.items.len > 0;
}

/// Check if the process should exit, accounting for native modules with background threads
/// This is more sophisticated than isEventLoopAlive() and handles cases where native
/// modules create persistent background threads that shouldn't prevent process exit
pub fn shouldExitProcess(vm: *const VirtualMachine) bool {
// If we have explicit JavaScript tasks, don't exit
if (vm.isEventLoopAlive()) {
return false;
}

// If there are no active handles at all, we can exit
const handle = vm.event_loop_handle orelse return true;
const active_count = if (comptime Environment.isWindows)
handle.active_handles
else
handle.active;

if (active_count == 0) {
return true;
}

// If we have active handles but no explicit tasks, this might be from
// native modules with background threads. In Node.js, such modules
// should not prevent the process from exiting.
//
// The key insight is that if we have:
// 1. No explicit JavaScript tasks (timers, promises, etc.)
// 2. Only background handles from native modules
// 3. No pending work
//
// Then we should allow the process to exit.
//
// Instead of using an arbitrary threshold, we check if the process
// has been "idle" (no JS tasks) and allow exit in that case.
// This matches Node.js behavior where native modules with background
// threads don't prevent process exit.
return true; // Allow exit when no explicit JS tasks remain
}

pub fn wakeup(this: *VirtualMachine) void {
this.eventLoop().wakeup();
}
Expand Down
2 changes: 2 additions & 0 deletions test_lzma_fix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require("lzma");
console.log("OK - process should exit normally now");