git-watchtower 1.14.1 → 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/server/process.js +74 -28
package/package.json
CHANGED
package/src/server/process.js
CHANGED
|
@@ -265,38 +265,13 @@ class ProcessManager {
|
|
|
265
265
|
return false;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
// Capture reference before nulling — needed for deferred
|
|
268
|
+
// Capture reference before nulling — needed for deferred force-kill
|
|
269
269
|
const proc = this.process;
|
|
270
270
|
|
|
271
|
-
// Try graceful shutdown first
|
|
272
271
|
if (process.platform === 'win32') {
|
|
273
|
-
|
|
274
|
-
spawn('taskkill', ['/pid', proc.pid.toString(), '/f', '/t']);
|
|
275
|
-
} catch (e) {
|
|
276
|
-
// Ignore taskkill errors
|
|
277
|
-
}
|
|
272
|
+
this._stopWindows(proc);
|
|
278
273
|
} else {
|
|
279
|
-
|
|
280
|
-
// Kill the entire process group (negative PID) so that
|
|
281
|
-
// grandchildren (e.g. npm -> node -> vite) are also terminated.
|
|
282
|
-
process.kill(-proc.pid, 'SIGTERM');
|
|
283
|
-
|
|
284
|
-
// Force kill after grace period
|
|
285
|
-
const forceKillTimeout = setTimeout(() => {
|
|
286
|
-
try {
|
|
287
|
-
process.kill(-proc.pid, 'SIGKILL');
|
|
288
|
-
} catch (e) {
|
|
289
|
-
// Process group may already be dead
|
|
290
|
-
}
|
|
291
|
-
}, KILL_GRACE_PERIOD);
|
|
292
|
-
|
|
293
|
-
// Clear timeout if process exits cleanly
|
|
294
|
-
proc.once('close', () => {
|
|
295
|
-
clearTimeout(forceKillTimeout);
|
|
296
|
-
});
|
|
297
|
-
} catch (e) {
|
|
298
|
-
// Process group may already be dead
|
|
299
|
-
}
|
|
274
|
+
this._stopUnix(proc);
|
|
300
275
|
}
|
|
301
276
|
|
|
302
277
|
this.process = null;
|
|
@@ -305,6 +280,77 @@ class ProcessManager {
|
|
|
305
280
|
return true;
|
|
306
281
|
}
|
|
307
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Unix stop: SIGTERM the process group, then SIGKILL after a grace period.
|
|
285
|
+
* The grace timer is unref'd so it doesn't keep the event loop alive when
|
|
286
|
+
* the main process wants to exit.
|
|
287
|
+
* @param {import('child_process').ChildProcess} proc
|
|
288
|
+
* @private
|
|
289
|
+
*/
|
|
290
|
+
_stopUnix(proc) {
|
|
291
|
+
// If the process has already exited, there's nothing to signal.
|
|
292
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return;
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
process.kill(-proc.pid, 'SIGTERM');
|
|
296
|
+
} catch (e) {
|
|
297
|
+
// Process group may already be dead
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const forceKillTimeout = setTimeout(() => {
|
|
302
|
+
// Re-check: process may have exited during the grace period.
|
|
303
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return;
|
|
304
|
+
try {
|
|
305
|
+
process.kill(-proc.pid, 'SIGKILL');
|
|
306
|
+
} catch (e) {
|
|
307
|
+
// Process group may already be dead
|
|
308
|
+
}
|
|
309
|
+
}, KILL_GRACE_PERIOD);
|
|
310
|
+
|
|
311
|
+
// Don't let this timer keep the event loop alive on shutdown.
|
|
312
|
+
forceKillTimeout.unref();
|
|
313
|
+
|
|
314
|
+
// Clear early if the process exits before the grace period.
|
|
315
|
+
proc.once('close', () => {
|
|
316
|
+
clearTimeout(forceKillTimeout);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Windows stop: taskkill /t (tree kill). If the process doesn't exit
|
|
322
|
+
* within the grace period, retry with /f (force).
|
|
323
|
+
* @param {import('child_process').ChildProcess} proc
|
|
324
|
+
* @private
|
|
325
|
+
*/
|
|
326
|
+
_stopWindows(proc) {
|
|
327
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return;
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
spawn('taskkill', ['/pid', proc.pid.toString(), '/t']);
|
|
331
|
+
} catch (e) {
|
|
332
|
+
// Ignore spawn errors (PID already gone, etc.)
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Fallback: force-kill if the process is still alive after the
|
|
337
|
+
// grace period. This mirrors the Unix SIGTERM → SIGKILL pattern.
|
|
338
|
+
const forceKillTimeout = setTimeout(() => {
|
|
339
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return;
|
|
340
|
+
try {
|
|
341
|
+
spawn('taskkill', ['/pid', proc.pid.toString(), '/f', '/t']);
|
|
342
|
+
} catch (e) {
|
|
343
|
+
// Ignore — process may already be dead
|
|
344
|
+
}
|
|
345
|
+
}, KILL_GRACE_PERIOD);
|
|
346
|
+
|
|
347
|
+
forceKillTimeout.unref();
|
|
348
|
+
|
|
349
|
+
proc.once('close', () => {
|
|
350
|
+
clearTimeout(forceKillTimeout);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
308
354
|
/**
|
|
309
355
|
* Restart the server process
|
|
310
356
|
* @returns {Promise<{success: boolean, error?: Error, pid?: number}>}
|