Skip to content
Open
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
30 changes: 30 additions & 0 deletions packages/core/src/services/executionLifecycleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,34 @@ export class ExecutionLifecycleService {
execution.writeInput?.(input);
}
}

static cleanupAll(): void {
for (const executionId of this.activeExecutions.keys()) {
try {
this.kill(executionId);
} catch {
// Ignore errors during global cleanup
}
}
}
}

// --- Global Cleanup Hooks ---
// Ensures that if the gemini-cli process exits or is killed,
// any spawned subprocesses (like node-pty shells) are terminated.
let hasCleanedUp = false;
const handleProcessExit = () => {
if (hasCleanedUp) return;
hasCleanedUp = true;
ExecutionLifecycleService.cleanupAll();
};

process.on('exit', handleProcessExit);
process.on('SIGINT', () => {
handleProcessExit();
process.exit(130);
});
process.on('SIGTERM', () => {
handleProcessExit();
process.exit(143);
});
Comment on lines +643 to +661
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Adding global process signal listeners (SIGINT, SIGTERM) in a core library package is problematic for two reasons:

  1. Side Effects on Import: Libraries should generally avoid modifying global state or attaching process-level listeners upon module import. This makes the code harder to test and can lead to unexpected behavior in different environments.
  2. Preempting Graceful Shutdown: The process.exit() calls in these handlers will terminate the process immediately after cleanupAll() runs. This preempts the CLI's own graceful shutdown logic in packages/cli/src/utils/cleanup.ts, which is responsible for critical asynchronous tasks like flushing telemetry, closing browser sessions, and disposing of configurations. If this core listener fires first, telemetry data will be lost.

These listeners should be removed from the core package. Instead, ExecutionLifecycleService.cleanupAll() should be registered with the CLI's existing cleanup utility (e.g., via registerSyncCleanup in packages/cli/src/utils/cleanup.ts) to ensure it runs as part of the established shutdown sequence.