
























@@ -31,6 +31,7 @@ const DEFAULT_MAX_COMMAND_RSS_MIB = 8192;
3131const DEFAULT_OUTPUT_CAPTURE_CHARS = 1024 * 1024;
3232const GATEWAY_TEARDOWN_GRACE_MS = 10000;
3333const GATEWAY_TEARDOWN_KILL_GRACE_MS = 2000;
34+const COMMAND_PARENT_SIGNAL_KILL_GRACE_MS = 2000;
3435const COMMAND_PROCESS_TREE_EXIT_POLL_MS = 50;
3536const LOG_SCAN_CHUNK_BYTES = 64 * 1024;
3637const LOG_SCAN_MAX_LINE_CHARS = 16 * 1024;
@@ -56,6 +57,40 @@ const ERROR_LOG_ALLOW_PATTERNS = [
5657];
57585859let callGatewayModulePromise;
60+const activeCommandChildren = new Set();
61+const commandParentSignals =
62+process.platform === "win32" ? ["SIGINT", "SIGTERM"] : ["SIGINT", "SIGTERM", "SIGHUP"];
63+let commandShutdownPromise;
64+let commandSignalHandlersInstalled = false;
65+66+function installCommandSignalHandlers() {
67+if (commandSignalHandlersInstalled) {
68+return;
69+}
70+commandSignalHandlersInstalled = true;
71+for (const signal of commandParentSignals) {
72+process.on(signal, commandSignalHandlers.get(signal));
73+}
74+}
75+76+function removeCommandSignalHandlers() {
77+if (!commandSignalHandlersInstalled) {
78+return;
79+}
80+commandSignalHandlersInstalled = false;
81+for (const signal of commandParentSignals) {
82+process.off(signal, commandSignalHandlers.get(signal));
83+}
84+}
85+86+const commandSignalHandlers = new Map(
87+commandParentSignals.map((signal) => [
88+signal,
89+() => {
90+void shutdownActiveCommands(signal);
91+},
92+]),
93+);
59946095function usage() {
6196return `Usage: node scripts/e2e/kitchen-sink-rpc-walk.mjs
@@ -301,6 +336,11 @@ function formatCapturedOutput(label, buffer) {
301336}
302337303338export function runCommand(command, args, options = {}) {
339+if (commandShutdownPromise) {
340+return commandShutdownPromise.then(() => {
341+throw new Error(`${command} ${args.join(" ")} skipped during parent signal shutdown`);
342+});
343+}
304344return new Promise((resolve, reject) => {
305345const config = resolveKitchenSinkRpcConfig();
306346const {
@@ -320,6 +360,8 @@ export function runCommand(command, args, options = {}) {
320360 ...spawnOptions,
321361detached: spawnOptions.detached ?? process.platform !== "win32",
322362});
363+activeCommandChildren.add(child);
364+installCommandSignalHandlers();
323365const startedAt = Date.now();
324366let stdout = { text: "", truncatedChars: 0 };
325367let stderr = { text: "", truncatedChars: 0 };
@@ -393,6 +435,7 @@ export function runCommand(command, args, options = {}) {
393435clearTimeout(timer);
394436clearTimeout(forceKillTimer);
395437forceKillAt = undefined;
438+releaseCommandChild(child);
396439void stopResourceSampling().finally(() =>
397440reject(toLintErrorObject(error, "Command failed before exit")),
398441);
@@ -402,6 +445,7 @@ export function runCommand(command, args, options = {}) {
402445const finish = () => {
403446clearTimeout(forceKillTimer);
404447forceKillAt = undefined;
448+releaseCommandChild(child);
405449void stopResourceSampling().then((resourceSampleFailure) => {
406450if (!timedOut && status === 0) {
407451if (resourceSampleFailure) {
@@ -470,6 +514,38 @@ async function finishTimedOutCommandProcessTree(child, { forceKillAt, timeoutKil
470514await waitForCommandProcessTreeExit(child, timeoutKillGraceMs);
471515}
472516517+function releaseCommandChild(child) {
518+activeCommandChildren.delete(child);
519+if (activeCommandChildren.size === 0 && !commandShutdownPromise) {
520+removeCommandSignalHandlers();
521+}
522+}
523+524+async function shutdownActiveCommands(signal) {
525+if (commandShutdownPromise) {
526+for (const child of activeCommandChildren) {
527+signalProcessGroup(child, "SIGKILL");
528+}
529+return commandShutdownPromise;
530+}
531+const children = [...activeCommandChildren];
532+for (const child of children) {
533+signalProcessGroup(child, signal);
534+}
535+commandShutdownPromise = Promise.all(
536+children.map((child) =>
537+finishTimedOutCommandProcessTree(child, {
538+forceKillAt: Date.now() + COMMAND_PARENT_SIGNAL_KILL_GRACE_MS,
539+timeoutKillGraceMs: COMMAND_PARENT_SIGNAL_KILL_GRACE_MS,
540+}),
541+),
542+).finally(() => {
543+removeCommandSignalHandlers();
544+process.kill(process.pid, signal);
545+});
546+return commandShutdownPromise;
547+}
548+473549async function waitForCommandProcessTreeExit(child, timeoutMs) {
474550const deadlineAt = Date.now() + timeoutMs;
475551while (Date.now() < deadlineAt) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。