procband 0.2.3 → 0.3.1
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 +18 -1
- package/dist/index.mjs +20 -4
- package/docs/context.md +39 -9
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChildProcess } from "node:child_process";
|
|
2
|
-
import { Writable } from "node:stream";
|
|
2
|
+
import { Readable, Writable } from "node:stream";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
/**
|
|
@@ -67,6 +67,23 @@ interface ProcessConfig {
|
|
|
67
67
|
* `process.stderr`.
|
|
68
68
|
*/
|
|
69
69
|
stderr?: Writable;
|
|
70
|
+
/**
|
|
71
|
+
* Child stdin behavior.
|
|
72
|
+
*
|
|
73
|
+
* Defaults to `false`, which connects the child stdin to the null device.
|
|
74
|
+
* Use `true` to expose a writable `proc.stdin`, or pass a readable stream to
|
|
75
|
+
* pipe bytes into the child automatically.
|
|
76
|
+
*/
|
|
77
|
+
stdin?: boolean | Readable;
|
|
78
|
+
/**
|
|
79
|
+
* Signal to send when the parent process is shutting down.
|
|
80
|
+
*
|
|
81
|
+
* When provided, `procband` uses this signal for parent-driven cleanup on
|
|
82
|
+
* `SIGINT`, `SIGTERM`, and `exit` instead of mirroring the parent signal or
|
|
83
|
+
* relying on the platform default. This only affects parent-driven cleanup;
|
|
84
|
+
* `proc.stop()` and `proc.kill()` still use their own explicit signals.
|
|
85
|
+
*/
|
|
86
|
+
parentExitSignal?: KillSignal;
|
|
70
87
|
/**
|
|
71
88
|
* Automatic restart behavior for terminal child exits.
|
|
72
89
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -494,13 +494,13 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
494
494
|
this.restartDisabled = true;
|
|
495
495
|
this.restart.cancelDelay();
|
|
496
496
|
const child = this.currentChild;
|
|
497
|
-
if (child) killTreeBestEffort(child);
|
|
497
|
+
if (child) killTreeBestEffort(child, this.getParentCleanupSignal());
|
|
498
498
|
}
|
|
499
499
|
async cleanupFromSignal(signal) {
|
|
500
500
|
this.shutdownRequested = true;
|
|
501
501
|
this.restartDisabled = true;
|
|
502
502
|
this.restart.cancelDelay();
|
|
503
|
-
await this.stopActiveTree(signal, 1e3);
|
|
503
|
+
await this.stopActiveTree(this.getParentCleanupSignal(signal), 1e3);
|
|
504
504
|
}
|
|
505
505
|
async stopActiveTree(signal, killAfterMs) {
|
|
506
506
|
const attempt = this.attempt;
|
|
@@ -510,13 +510,16 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
510
510
|
}
|
|
511
511
|
await stopChildTree(attempt.child, attempt.close, () => attempt.closed, signal, killAfterMs);
|
|
512
512
|
}
|
|
513
|
+
getParentCleanupSignal(fallback) {
|
|
514
|
+
return this.config.parentExitSignal ?? fallback;
|
|
515
|
+
}
|
|
513
516
|
spawnAttempt() {
|
|
514
517
|
this.generation += 1;
|
|
515
518
|
const child = spawn(this.config.command, this.config.args ?? [], {
|
|
516
519
|
cwd: this.config.cwd,
|
|
517
520
|
env: this.config.env,
|
|
518
521
|
stdio: [
|
|
519
|
-
"pipe",
|
|
522
|
+
this.config.stdin ? "pipe" : "ignore",
|
|
520
523
|
"pipe",
|
|
521
524
|
"pipe"
|
|
522
525
|
]
|
|
@@ -537,13 +540,15 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
537
540
|
text: "",
|
|
538
541
|
flushed: false
|
|
539
542
|
},
|
|
540
|
-
closed: false
|
|
543
|
+
closed: false,
|
|
544
|
+
stdinCleanup: null
|
|
541
545
|
};
|
|
542
546
|
this.attempt = attempt;
|
|
543
547
|
this.attachAttempt(attempt);
|
|
544
548
|
}
|
|
545
549
|
attachAttempt(attempt) {
|
|
546
550
|
const { child } = attempt;
|
|
551
|
+
attempt.stdinCleanup = this.bindAttemptStdin(attempt);
|
|
547
552
|
child.on("spawn", () => {
|
|
548
553
|
if (this.attempt === attempt) this.emit("spawn");
|
|
549
554
|
});
|
|
@@ -556,6 +561,8 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
556
561
|
child.on("close", (code, signal) => {
|
|
557
562
|
if (this.attempt !== attempt) return;
|
|
558
563
|
attempt.closed = true;
|
|
564
|
+
attempt.stdinCleanup?.();
|
|
565
|
+
attempt.stdinCleanup = null;
|
|
559
566
|
this.flushLineBuffer(attempt, "stdout");
|
|
560
567
|
this.flushLineBuffer(attempt, "stderr");
|
|
561
568
|
attempt.settleClose({
|
|
@@ -682,6 +689,15 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
682
689
|
buffer.text = "";
|
|
683
690
|
this.handleLine(stream, line, false);
|
|
684
691
|
}
|
|
692
|
+
bindAttemptStdin(attempt) {
|
|
693
|
+
const source = this.config.stdin;
|
|
694
|
+
const destination = attempt.child.stdin;
|
|
695
|
+
if (!destination || typeof source !== "object") return null;
|
|
696
|
+
source.pipe(destination);
|
|
697
|
+
return () => {
|
|
698
|
+
source.unpipe(destination);
|
|
699
|
+
};
|
|
700
|
+
}
|
|
685
701
|
};
|
|
686
702
|
const liveProcesses = /* @__PURE__ */ new Set();
|
|
687
703
|
let propagatedFailure = false;
|
package/docs/context.md
CHANGED
|
@@ -7,7 +7,7 @@ The returned `ProcbandProcess` is both:
|
|
|
7
7
|
- a `ChildProcess`-compatible handle for the current active child attempt
|
|
8
8
|
- a thenable wrapper that resolves to a `ProcessResult` when supervision is done
|
|
9
9
|
|
|
10
|
-
Supervision adds
|
|
10
|
+
Supervision adds five behaviors on top of raw `spawn()`:
|
|
11
11
|
|
|
12
12
|
- prefixed `stdout` and `stderr`
|
|
13
13
|
- line-based matching for future output
|
|
@@ -35,8 +35,9 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
35
35
|
# Core Abstractions
|
|
36
36
|
|
|
37
37
|
- `ProcessConfig`
|
|
38
|
-
Declares one supervised subprocess plus its label, color, restart policy,
|
|
39
|
-
optional
|
|
38
|
+
Declares one supervised subprocess plus its label, color, restart policy,
|
|
39
|
+
optional stdin behavior, optional parent-exit signal override, and optional
|
|
40
|
+
raw `stderr` tee.
|
|
40
41
|
- `ProcbandProcess`
|
|
41
42
|
The live wrapper returned by `supervise()`. It is a `ChildProcess`-compatible
|
|
42
43
|
handle, a matching surface, a shutdown surface, and a thenable final result.
|
|
@@ -52,14 +53,17 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
52
53
|
3. Each line is prefixed and written to the parent `process.stdout` or
|
|
53
54
|
`process.stderr`.
|
|
54
55
|
4. `stderr` can also be tee'd as raw bytes to `ProcessConfig.stderr`.
|
|
55
|
-
5.
|
|
56
|
+
5. `stdin` is disconnected by default. Set `ProcessConfig.stdin` to `true` for
|
|
57
|
+
a writable child stdin, or pass a readable stream to pipe input into the
|
|
58
|
+
child automatically.
|
|
59
|
+
6. Future matching lines are delivered through `match()` callbacks or
|
|
56
60
|
`waitFor()`.
|
|
57
|
-
|
|
61
|
+
7. When a child exits, `procband` either finalizes or starts a new attempt,
|
|
58
62
|
depending on the restart policy.
|
|
59
|
-
|
|
63
|
+
8. A terminal failed exit that nobody observed through `await proc` or
|
|
60
64
|
`proc.wait()` sets `process.exitCode` and begins
|
|
61
65
|
stopping any other live `procband` processes in the same parent script.
|
|
62
|
-
|
|
66
|
+
9. `await proc` or `await proc.wait()` resolves only after the process is
|
|
63
67
|
terminal and no further restart will happen.
|
|
64
68
|
|
|
65
69
|
# Common Tasks -> Recommended APIs
|
|
@@ -78,10 +82,34 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
78
82
|
Do not call `wait()` or await the thenable result
|
|
79
83
|
- Capture raw child `stderr` in a file or custom stream:
|
|
80
84
|
`ProcessConfig.stderr`
|
|
85
|
+
- Write to child stdin manually:
|
|
86
|
+
`stdin: true`, then `proc.stdin?.write(...)`
|
|
87
|
+
- Pipe a custom input stream into the child:
|
|
88
|
+
`stdin: readable`
|
|
81
89
|
- Retry failed exits with sane defaults:
|
|
82
90
|
`restart: true`
|
|
83
91
|
- Use explicit retry rules:
|
|
84
92
|
`restart: { when, delayMs, maxFailures, windowMs }`
|
|
93
|
+
- Force a specific signal during parent shutdown:
|
|
94
|
+
`parentExitSignal: 'SIGHUP'`
|
|
95
|
+
|
|
96
|
+
# Recommended Patterns
|
|
97
|
+
|
|
98
|
+
- Use `proc.stop()` for deliberate shutdown initiated by your own script.
|
|
99
|
+
- Reserve `parentExitSignal` for children that expect a specific signal from
|
|
100
|
+
their supervisor during parent-driven cleanup.
|
|
101
|
+
- Await `proc` or call `proc.wait()` when your script intends to own failure
|
|
102
|
+
handling instead of inheriting procband's default parent-exit propagation.
|
|
103
|
+
|
|
104
|
+
# Patterns to Avoid
|
|
105
|
+
|
|
106
|
+
- Do not treat `parentExitSignal` as a replacement for `StopOptions.signal`.
|
|
107
|
+
The former only changes parent-driven cleanup; the latter controls
|
|
108
|
+
explicit `proc.stop()` calls.
|
|
109
|
+
- Do not rely on `kill()` for full shutdown when descendants may still be
|
|
110
|
+
running. `kill()` only targets the current direct child.
|
|
111
|
+
- Do not expect historical log replay from `match()` or `waitFor()`. Matching
|
|
112
|
+
is future-only by design.
|
|
85
113
|
|
|
86
114
|
# Invariants and Constraints
|
|
87
115
|
|
|
@@ -102,11 +130,13 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
102
130
|
processes in the same parent script.
|
|
103
131
|
- The wrapper survives restarts, but inherited `pid`, `stdin`, `stdout`,
|
|
104
132
|
`stderr`, and related `ChildProcess` fields always refer to the current active
|
|
105
|
-
child attempt.
|
|
133
|
+
child attempt. `stdin` is `null` unless `ProcessConfig.stdin` is enabled.
|
|
106
134
|
- `kill()` only signals the current direct child. `stop()` disables restart and
|
|
107
135
|
kills the full process tree.
|
|
108
136
|
- Parent cleanup installs both `SIGINT` and `SIGTERM` handlers while any live
|
|
109
|
-
supervised process exists.
|
|
137
|
+
supervised process exists. Set `ProcessConfig.parentExitSignal` to override
|
|
138
|
+
which signal is sent to the child tree during parent-driven cleanup. This
|
|
139
|
+
does not change the signal used by explicit `proc.stop()` calls.
|
|
110
140
|
- `stderr` prefixes always use the reserved red, even when a custom process
|
|
111
141
|
color is configured.
|
|
112
142
|
- `ProcessConfig.name` is optional. When omitted, it falls back to the
|
package/package.json
CHANGED