


















@@ -173,6 +173,8 @@ const DEFAULT_TIMEOUT_MS = 30_000;
173173const DEFAULT_POST_READY_DELAY_MS = 250;
174174const DEFAULT_ENTRY = "dist/entry.js";
175175const RESTART_INTENT_FILENAME = "gateway-restart-intent.json";
176+const TEARDOWN_GRACE_MS = 2_000;
177+const TEARDOWN_KILL_GRACE_MS = 1_000;
176178177179const BASE_CONFIG = {
178180browser: { enabled: false },
@@ -879,7 +881,10 @@ function writeRestartIntent(env: NodeJS.ProcessEnv, targetPid: number, reason: s
879881}
880882}
881883882-async function stopChild(child: ChildProcessWithoutNullStreams): Promise<StopChildResult> {
884+async function stopChild(
885+child: ChildProcessWithoutNullStreams,
886+options: { killGraceMs?: number; teardownGraceMs?: number } = {},
887+): Promise<StopChildResult> {
883888const currentExit = (): ChildExit | null =>
884889child.exitCode != null || child.signalCode != null
885890 ? { exitCode: child.exitCode, signal: child.signalCode }
@@ -897,22 +902,48 @@ async function stopChild(child: ChildProcessWithoutNullStreams): Promise<StopChi
897902resolve(observedExit);
898903});
899904});
905+const waitForExit = async (ms: number): Promise<ChildExit | null> =>
906+await Promise.race([exited, delay(ms).then(() => null)]);
900907901908await new Promise<void>((resolve) => setImmediate(resolve));
902909const queuedExit = observedExit ?? currentExit();
903910if (queuedExit != null) {
904911return { ...queuedExit, exitedBeforeTeardown: true };
905912}
906913914+const teardownGraceMs = options.teardownGraceMs ?? TEARDOWN_GRACE_MS;
915+const killGraceMs = options.killGraceMs ?? TEARDOWN_KILL_GRACE_MS;
907916const sentTeardownSignal = killProcessTree(child, "SIGTERM");
908-const timeout = delay(2000).then(() => {
909-if (child.exitCode == null && child.signalCode == null) {
910-killProcessTree(child, "SIGKILL");
911-}
912-return exited;
913-});
914-const exit = await Promise.race([exited, timeout]);
915-return { ...exit, exitedBeforeTeardown: !sentTeardownSignal };
917+const gracefulExit = await waitForExit(teardownGraceMs);
918+if (gracefulExit != null) {
919+return { ...gracefulExit, exitedBeforeTeardown: !sentTeardownSignal };
920+}
921+922+const postGraceExit = currentExit() ?? observedExit;
923+if (postGraceExit != null) {
924+return { ...postGraceExit, exitedBeforeTeardown: !sentTeardownSignal };
925+}
926+if (!sentTeardownSignal) {
927+releaseUnsettledChild(child);
928+return { exitCode: null, exitedBeforeTeardown: true, signal: null };
929+}
930+931+killProcessTree(child, "SIGKILL");
932+const killedExit = await waitForExit(killGraceMs);
933+const finalExit = killedExit ?? currentExit() ?? observedExit;
934+if (finalExit != null) {
935+return { ...finalExit, exitedBeforeTeardown: false };
936+}
937+938+releaseUnsettledChild(child);
939+return { exitCode: null, exitedBeforeTeardown: false, signal: "SIGKILL" };
940+}
941+942+function releaseUnsettledChild(child: ChildProcessWithoutNullStreams): void {
943+child.stdin.destroy();
944+child.stdout.destroy();
945+child.stderr.destroy();
946+child.unref();
916947}
917948918949function killProcessTree(child: ChildProcessWithoutNullStreams, signal: NodeJS.Signals): boolean {
@@ -1559,7 +1590,8 @@ async function runGatewaySample(options: {
15591590const exit = await stopChild(child);
15601591clearInterval(rssTimer);
15611592sampleRss();
1562-await childExitPromise.catch(() => null);
1593+// stopChild is the bounded teardown wait; the raw exit promise may never settle.
1594+void childExitPromise.catch(() => null);
15631595flushOutputLineBuffers(outputBuffers, onLine, performance.now() - sampleStartAt, {
15641596flushPartial: true,
15651597});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。