Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a623ac5fe4 | |||
| 34b9aa4463 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@push.rocks/smartexit",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"private": false,
|
||||
"description": "A library for managing graceful shutdowns of Node.js processes by handling cleanup operations, including terminating child processes.",
|
||||
"main": "dist_ts/index.js",
|
||||
|
||||
@@ -187,22 +187,18 @@ export class ProcessLifecycle {
|
||||
});
|
||||
}
|
||||
|
||||
/** Synchronous last-resort: SIGKILL any remaining child processes. */
|
||||
/** Synchronous last-resort: SIGKILL any remaining tracked PIDs. */
|
||||
private handleExit(): void {
|
||||
const instances = ProcessLifecycle.getInstances();
|
||||
let killed = 0;
|
||||
|
||||
for (const instance of instances) {
|
||||
const processes = instance.processesToEnd.getArray();
|
||||
for (const child of processes) {
|
||||
const pid = child.pid;
|
||||
if (pid && !child.killed) {
|
||||
try {
|
||||
process.kill(pid, 'SIGKILL');
|
||||
killed++;
|
||||
} catch {
|
||||
// Process may already be dead
|
||||
}
|
||||
for (const pid of instance.trackedPids) {
|
||||
try {
|
||||
process.kill(pid, 'SIGKILL');
|
||||
killed++;
|
||||
} catch {
|
||||
// Process already dead
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ export class SmartExit {
|
||||
// Instance state
|
||||
public processesToEnd = new plugins.lik.ObjectMap<plugins.childProcess.ChildProcess>();
|
||||
public cleanupFunctions = new plugins.lik.ObjectMap<() => Promise<any>>();
|
||||
/** PIDs tracked independently — survives removeProcess() so shutdown can still kill the tree. */
|
||||
public trackedPids = new Set<number>();
|
||||
private options: ISmartExitOptions;
|
||||
|
||||
private log(message: string, isError = false): void {
|
||||
@@ -93,6 +95,9 @@ export class SmartExit {
|
||||
/** Register a child process for cleanup on shutdown. */
|
||||
public addProcess(childProcessArg: plugins.childProcess.ChildProcess) {
|
||||
this.processesToEnd.add(childProcessArg);
|
||||
if (childProcessArg.pid) {
|
||||
this.trackedPids.add(childProcessArg.pid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Register an async cleanup function to run on shutdown. */
|
||||
@@ -126,23 +131,25 @@ export class SmartExit {
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Kill child process trees
|
||||
for (const childProcessArg of processes) {
|
||||
const pid = childProcessArg.pid;
|
||||
if (pid && !childProcessArg.killed) {
|
||||
try {
|
||||
await SmartExit.killTreeByPid(pid, 'SIGTERM');
|
||||
} catch {
|
||||
// SIGTERM failed — force kill
|
||||
try {
|
||||
await SmartExit.killTreeByPid(pid, 'SIGKILL');
|
||||
} catch {
|
||||
// Process may already be dead
|
||||
}
|
||||
}
|
||||
// Phase 2: Kill ALL tracked process trees by PID.
|
||||
// We use trackedPids (not processesToEnd) because the process object may have
|
||||
// been removed by smartshell's exit handler before shutdown runs.
|
||||
// We do NOT check .killed — the direct child may be dead but grandchildren alive.
|
||||
for (const pid of this.trackedPids) {
|
||||
try {
|
||||
await SmartExit.killTreeByPid(pid, 'SIGTERM');
|
||||
processesKilled++;
|
||||
} catch {
|
||||
// SIGTERM failed — force kill
|
||||
try {
|
||||
await SmartExit.killTreeByPid(pid, 'SIGKILL');
|
||||
processesKilled++;
|
||||
} catch {
|
||||
// Process tree already dead — fine
|
||||
}
|
||||
}
|
||||
}
|
||||
this.trackedPids.clear();
|
||||
|
||||
return { processesKilled, cleanupFunctionsRan };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user