procband 0.3.3 → 0.3.5
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/dist/index.d.mts +6 -2
- package/dist/index.mjs +20 -4
- package/docs/context.md +11 -5
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -50,7 +50,10 @@ interface ProcessConfig {
|
|
|
50
50
|
/**
|
|
51
51
|
* Whether to spawn the child in a detached process group/session.
|
|
52
52
|
*
|
|
53
|
-
* This is passed through to Node.js `spawn()` unchanged.
|
|
53
|
+
* This is passed through to Node.js `spawn()` unchanged. On Unix-like
|
|
54
|
+
* platforms, shutdown also signals the detached child's process group so
|
|
55
|
+
* same-group descendants are cleaned up even if they are no longer reachable
|
|
56
|
+
* through the child process tree.
|
|
54
57
|
*/
|
|
55
58
|
detached?: boolean;
|
|
56
59
|
/**
|
|
@@ -263,7 +266,8 @@ interface ProcbandProcess extends ChildProcess, PromiseLike<ProcessResult> {
|
|
|
263
266
|
* Disable future restarts and terminate the active process tree.
|
|
264
267
|
*
|
|
265
268
|
* For supervised processes, `kill()` targets the current child process and
|
|
266
|
-
* any descendants it spawned instead of only the direct child.
|
|
269
|
+
* any descendants it spawned instead of only the direct child. Detached
|
|
270
|
+
* Unix-like children are also stopped by process group.
|
|
267
271
|
* `kill(0)` preserves the normal `ChildProcess` existence-check behavior.
|
|
268
272
|
*/
|
|
269
273
|
kill(signal?: KillSignal): boolean;
|
package/dist/index.mjs
CHANGED
|
@@ -290,18 +290,23 @@ function unregisterCleanupTarget(target) {
|
|
|
290
290
|
liveTargets.delete(target);
|
|
291
291
|
if (liveTargets.size === 0) uninstallParentCleanup();
|
|
292
292
|
}
|
|
293
|
-
function killTreeBestEffort(child, signal) {
|
|
293
|
+
function killTreeBestEffort(child, signal, options = {}) {
|
|
294
|
+
if (options.detached) try {
|
|
295
|
+
killProcessGroup(child, signal);
|
|
296
|
+
} catch {}
|
|
294
297
|
try {
|
|
295
298
|
treeKillSync(child, signal);
|
|
296
299
|
} catch {}
|
|
297
300
|
}
|
|
298
|
-
async function stopChildTree(child, close, isClosed, signal, killAfterMs) {
|
|
301
|
+
async function stopChildTree(child, close, isClosed, signal, killAfterMs, options = {}) {
|
|
302
|
+
if (options.detached) killProcessGroup(child, signal);
|
|
299
303
|
try {
|
|
300
304
|
await treeKill(child, signal);
|
|
301
305
|
} catch (error) {
|
|
302
306
|
if (!isMissingProcessError(error)) throw error;
|
|
303
307
|
}
|
|
304
308
|
if (!await Promise.race([close.then(() => true), setTimeout$1(killAfterMs, false)]) && !isClosed()) {
|
|
309
|
+
if (options.detached) killProcessGroup(child, "SIGKILL");
|
|
305
310
|
try {
|
|
306
311
|
await treeKill(child, "SIGKILL");
|
|
307
312
|
} catch (error) {
|
|
@@ -310,6 +315,14 @@ async function stopChildTree(child, close, isClosed, signal, killAfterMs) {
|
|
|
310
315
|
await close;
|
|
311
316
|
}
|
|
312
317
|
}
|
|
318
|
+
function killProcessGroup(child, signal) {
|
|
319
|
+
if (process.platform === "win32" || !child.pid) return;
|
|
320
|
+
try {
|
|
321
|
+
process.kill(-child.pid, signal);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (!isMissingProcessError(error)) throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
313
326
|
function installParentCleanup() {
|
|
314
327
|
if (parentCleanupInstalled) return;
|
|
315
328
|
parentCleanupInstalled = true;
|
|
@@ -508,7 +521,7 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
508
521
|
cleanupFromExit() {
|
|
509
522
|
this.prepareShutdown();
|
|
510
523
|
const child = this.currentChild;
|
|
511
|
-
if (child) killTreeBestEffort(child, this.getParentCleanupSignal());
|
|
524
|
+
if (child) killTreeBestEffort(child, this.getParentCleanupSignal(), { detached: this.config.detached });
|
|
512
525
|
}
|
|
513
526
|
async cleanupFromSignal(signal) {
|
|
514
527
|
await this.beginShutdown(this.getParentCleanupSignal(signal), 1e3);
|
|
@@ -519,7 +532,7 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
519
532
|
await this.finalPromise;
|
|
520
533
|
return;
|
|
521
534
|
}
|
|
522
|
-
await stopChildTree(attempt.child, attempt.close, () => attempt.closed, signal, killAfterMs);
|
|
535
|
+
await stopChildTree(attempt.child, attempt.close, () => attempt.closed, signal, killAfterMs, { detached: this.config.detached });
|
|
523
536
|
}
|
|
524
537
|
getParentCleanupSignal(fallback) {
|
|
525
538
|
return this.config.parentExitSignal ?? fallback;
|
|
@@ -738,6 +751,9 @@ function propagateFailure(exitCode) {
|
|
|
738
751
|
propagatedFailure = true;
|
|
739
752
|
if (process.exitCode == null || process.exitCode === 0) process.exitCode = exitCode;
|
|
740
753
|
for (const proc of liveProcesses) proc.kill();
|
|
754
|
+
setImmediate(() => {
|
|
755
|
+
process.exit(process.exitCode ?? exitCode);
|
|
756
|
+
});
|
|
741
757
|
}
|
|
742
758
|
//#endregion
|
|
743
759
|
export { supervise };
|
package/docs/context.md
CHANGED
|
@@ -12,7 +12,7 @@ Supervision adds five behaviors on top of raw `spawn()`:
|
|
|
12
12
|
- prefixed `stdout` and `stderr`
|
|
13
13
|
- line-based matching for future output
|
|
14
14
|
- optional restart policy with failure suppression
|
|
15
|
-
-
|
|
15
|
+
- shutdown for the child and descendants, including detached Unix process groups
|
|
16
16
|
- parent-exit propagation for unobserved terminal failures
|
|
17
17
|
|
|
18
18
|
# When to Use
|
|
@@ -96,6 +96,9 @@ Supervision adds five behaviors on top of raw `spawn()`:
|
|
|
96
96
|
# Recommended Patterns
|
|
97
97
|
|
|
98
98
|
- Use `proc.kill()` for deliberate shutdown initiated by your own script.
|
|
99
|
+
- Use `detached: true` when a child must run in its own process group/session.
|
|
100
|
+
On Unix-like platforms, `procband` uses that process group during shutdown in
|
|
101
|
+
addition to process-tree cleanup.
|
|
99
102
|
- Reserve `parentExitSignal` for children that expect a specific signal from
|
|
100
103
|
their supervisor during parent-driven cleanup.
|
|
101
104
|
- Await `proc` or call `proc.wait()` when your script intends to own failure
|
|
@@ -130,12 +133,15 @@ Supervision adds five behaviors on top of raw `spawn()`:
|
|
|
130
133
|
- The wrapper survives restarts, but inherited `pid`, `stdin`, `stdout`,
|
|
131
134
|
`stderr`, and related `ChildProcess` fields always refer to the current active
|
|
132
135
|
child attempt. `stdin` is `null` unless `ProcessConfig.stdin` is enabled.
|
|
133
|
-
- `kill()` disables future restarts and kills the full process tree
|
|
134
|
-
`
|
|
136
|
+
- `kill()` disables future restarts and kills the full process tree. For
|
|
137
|
+
`detached: true` children on Unix-like platforms, shutdown also signals the
|
|
138
|
+
detached child's process group so same-group descendants are cleaned up even
|
|
139
|
+
when they are no longer reachable by parent PID. `kill(0)` only checks
|
|
140
|
+
whether the current child attempt exists.
|
|
135
141
|
- Parent cleanup installs both `SIGINT` and `SIGTERM` handlers while any live
|
|
136
142
|
supervised process exists. Set `ProcessConfig.parentExitSignal` to override
|
|
137
|
-
which signal is sent
|
|
138
|
-
|
|
143
|
+
which signal is sent during parent-driven cleanup. This does not change the
|
|
144
|
+
signal used by explicit `proc.kill()` calls.
|
|
139
145
|
- `stderr` prefixes always use the reserved red, even when a custom process
|
|
140
146
|
color is configured.
|
|
141
147
|
- `ProcessConfig.name` is optional. When omitted, it falls back to the
|
package/package.json
CHANGED