























@@ -3,6 +3,8 @@ import { buildCmdExeCommandLine } from "../windows-cmd-helpers.mjs";
3344const FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
55const FORCE_KILL_DELAY_MS = 5_000;
6+const managedChildren = new Set();
7+const signalHandlers = new Map();
6879/**
810 * @param {NodeJS.Signals} signal
@@ -80,37 +82,83 @@ export async function runManagedCommand({
8082 comSpec,
8183});
8284const child = spawn(spawnSpec.command, spawnSpec.args, spawnSpec.options);
83-84-let receivedSignal = null;
85-let forceKillTimer = null;
86-87-const forwardSignal = (signal) => {
88-receivedSignal ??= signal;
89-terminateManagedChild(child, signal);
90-forceKillTimer ??= setTimeout(() => {
91-terminateManagedChild(child, "SIGKILL");
92-}, FORCE_KILL_DELAY_MS);
85+const managedChild = {
86+ child,
87+forceKillTimer: null,
88+receivedSignal: null,
9389};
94-95-for (const signal of FORWARDED_SIGNALS) {
96-process.once(signal, forwardSignal);
97-}
90+addManagedChild(managedChild);
9891onReady?.(child);
999210093try {
10194return await new Promise((resolve, reject) => {
10295child.once("error", reject);
10396child.once("close", (status) => {
104-if (forceKillTimer) {
105-clearTimeout(forceKillTimer);
97+if (managedChild.forceKillTimer) {
98+clearTimeout(managedChild.forceKillTimer);
10699}
107-resolve(receivedSignal ? signalExitCode(receivedSignal) : (status ?? 1));
100+resolve(managedChild.receivedSignal ? signalExitCode(managedChild.receivedSignal) : (status ?? 1));
108101});
109102});
110103} finally {
111-for (const signal of FORWARDED_SIGNALS) {
112-process.off(signal, forwardSignal);
104+removeManagedChild(managedChild);
105+}
106+}
107+108+/**
109+ * @param {{
110+ * child: import("node:child_process").ChildProcess;
111+ * forceKillTimer: NodeJS.Timeout | null;
112+ * receivedSignal: NodeJS.Signals | null;
113+ * }} managedChild
114+ */
115+function addManagedChild(managedChild) {
116+managedChildren.add(managedChild);
117+installSignalHandlers();
118+}
119+120+/**
121+ * @param {{
122+ * child: import("node:child_process").ChildProcess;
123+ * forceKillTimer: NodeJS.Timeout | null;
124+ * receivedSignal: NodeJS.Signals | null;
125+ * }} managedChild
126+ */
127+function removeManagedChild(managedChild) {
128+managedChildren.delete(managedChild);
129+if (managedChildren.size === 0) {
130+removeSignalHandlers();
131+}
132+}
133+134+function installSignalHandlers() {
135+for (const signal of FORWARDED_SIGNALS) {
136+if (signalHandlers.has(signal)) {
137+continue;
113138}
139+const handler = () => forwardSignalToManagedChildren(signal);
140+signalHandlers.set(signal, handler);
141+process.on(signal, handler);
142+}
143+}
144+145+function removeSignalHandlers() {
146+for (const [signal, handler] of signalHandlers) {
147+process.off(signal, handler);
148+}
149+signalHandlers.clear();
150+}
151+152+/**
153+ * @param {NodeJS.Signals} signal
154+ */
155+function forwardSignalToManagedChildren(signal) {
156+for (const managedChild of managedChildren) {
157+managedChild.receivedSignal ??= signal;
158+terminateManagedChild(managedChild.child, signal);
159+managedChild.forceKillTimer ??= setTimeout(() => {
160+terminateManagedChild(managedChild.child, "SIGKILL");
161+}, FORCE_KILL_DELAY_MS);
114162}
115163}
116164此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。