@nwire/supervisor 0.12.0 → 0.13.0
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/supervisor.js +28 -1
- package/package.json +1 -1
package/dist/supervisor.js
CHANGED
|
@@ -109,9 +109,28 @@ export class RunnerSupervisor extends EventEmitter {
|
|
|
109
109
|
};
|
|
110
110
|
child.stdout?.on("data", capture("stdout"));
|
|
111
111
|
child.stderr?.on("data", capture("stderr"));
|
|
112
|
+
// A supervised child must never keep the supervisor's own process alive:
|
|
113
|
+
// unref the child handle and its stdio pipes so an in-flight or
|
|
114
|
+
// not-yet-stopped child can't block the parent (or a test runner's
|
|
115
|
+
// worker) from exiting. Data is still captured — unref only detaches the
|
|
116
|
+
// handles from the event-loop keep-alive set, it doesn't stop them.
|
|
117
|
+
child.unref();
|
|
118
|
+
// The piped stdio streams are Sockets at runtime (they carry `.unref`)
|
|
119
|
+
// but typed as the base `Readable`, which doesn't declare it.
|
|
120
|
+
const unref = (s) => {
|
|
121
|
+
s?.unref?.();
|
|
122
|
+
};
|
|
123
|
+
unref(child.stdout);
|
|
124
|
+
unref(child.stderr);
|
|
112
125
|
child.on("exit", (code, signal) => {
|
|
113
126
|
proc.exitCode = code;
|
|
114
127
|
proc.signal = signal;
|
|
128
|
+
// Release the child's stdout/stderr pipes. Node keeps the underlying
|
|
129
|
+
// PipeWrap handles alive until the readable side is destroyed; without
|
|
130
|
+
// this, an exited child leaves open handles that keep the parent (or a
|
|
131
|
+
// test runner's worker) from exiting cleanly.
|
|
132
|
+
child.stdout?.destroy();
|
|
133
|
+
child.stderr?.destroy();
|
|
115
134
|
// Distinguish clean stop (we asked for it) from a crash.
|
|
116
135
|
if (proc.status === "stopping") {
|
|
117
136
|
proc.status = "exited";
|
|
@@ -193,8 +212,16 @@ export class RunnerSupervisor extends EventEmitter {
|
|
|
193
212
|
this.emit("status", id, "stopping", state.proc);
|
|
194
213
|
state.child.kill("SIGTERM");
|
|
195
214
|
const exited = new Promise((resolve) => state.child.once("exit", () => resolve()));
|
|
196
|
-
|
|
215
|
+
// Hold the timer handle so we can clear it the moment the child exits —
|
|
216
|
+
// an uncleared grace timer is a ref'd setTimeout that keeps the process
|
|
217
|
+
// (and a test runner's worker) alive for the full graceMs window.
|
|
218
|
+
let graceTimer;
|
|
219
|
+
const grace = new Promise((resolve) => {
|
|
220
|
+
graceTimer = setTimeout(() => resolve("escalate"), graceMs);
|
|
221
|
+
});
|
|
197
222
|
const result = await Promise.race([exited.then(() => "exited"), grace]);
|
|
223
|
+
if (graceTimer)
|
|
224
|
+
clearTimeout(graceTimer);
|
|
198
225
|
if (result === "escalate") {
|
|
199
226
|
try {
|
|
200
227
|
// Windows collapses SIGTERM and SIGKILL into the same hard
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nwire/supervisor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Spawns and watches Nwire wire processes for dev tooling. Used by `nwire dev` and Studio's vite dev server. Generic process supervisor with stdout/stderr ring buffer, health-check polling, SIGTERM-then-SIGKILL graceful stop.",
|
|
6
6
|
"keywords": [
|