




















@@ -68,6 +68,15 @@ type GatewayRestartFailureCode =
6868| "child_nonzero_exit"
6969| "cleanup_failed";
707071+type ChildExit = {
72+exitCode: number | null;
73+signal: string | null;
74+};
75+76+type StopChildResult = ChildExit & {
77+exitedBeforeTeardown: boolean;
78+};
79+7180type RestartIteration = {
7281cpuCoreRatio: number | null;
7382cpuMs: number | null;
@@ -98,6 +107,7 @@ type GatewayRestartSample = {
98107childExitCode: number | null;
99108childSignal: string | null;
100109events: BenchmarkEvent[];
110+exitedBeforeTeardown: boolean;
101111failureCode: GatewayRestartFailureCode | null;
102112firstOutputMs: number | null;
103113initialGatewayReadyLogLine: string | null;
@@ -869,36 +879,52 @@ function writeRestartIntent(env: NodeJS.ProcessEnv, targetPid: number, reason: s
869879}
870880}
871881872-async function stopChild(child: ChildProcessWithoutNullStreams): Promise<{
873-exitCode: number | null;
874-signal: string | null;
875-}> {
876-if (child.exitCode != null || child.signalCode != null) {
877-return { exitCode: child.exitCode, signal: child.signalCode };
882+async function stopChild(child: ChildProcessWithoutNullStreams): Promise<StopChildResult> {
883+const currentExit = (): ChildExit | null =>
884+child.exitCode != null || child.signalCode != null
885+ ? { exitCode: child.exitCode, signal: child.signalCode }
886+ : null;
887+888+const existingExit = currentExit();
889+if (existingExit != null) {
890+return { ...existingExit, exitedBeforeTeardown: true };
878891}
879-const exited = new Promise<{ exitCode: number | null; signal: string | null }>((resolve) => {
880-child.once("exit", (exitCode, signal) => resolve({ exitCode, signal }));
892+893+let observedExit: ChildExit | null = null;
894+const exited = new Promise<ChildExit>((resolve) => {
895+child.once("exit", (exitCode, signal) => {
896+observedExit = { exitCode, signal };
897+resolve(observedExit);
898+});
881899});
882-killProcessTree(child, "SIGTERM");
900+901+await new Promise<void>((resolve) => setImmediate(resolve));
902+const queuedExit = observedExit ?? currentExit();
903+if (queuedExit != null) {
904+return { ...queuedExit, exitedBeforeTeardown: true };
905+}
906+907+const sentTeardownSignal = killProcessTree(child, "SIGTERM");
883908const timeout = delay(2000).then(() => {
884909if (child.exitCode == null && child.signalCode == null) {
885910killProcessTree(child, "SIGKILL");
886911}
887912return exited;
888913});
889-return Promise.race([exited, timeout]);
914+const exit = await Promise.race([exited, timeout]);
915+return { ...exit, exitedBeforeTeardown: !sentTeardownSignal };
890916}
891917892-function killProcessTree(child: ChildProcessWithoutNullStreams, signal: NodeJS.Signals): void {
918+function killProcessTree(child: ChildProcessWithoutNullStreams, signal: NodeJS.Signals): boolean {
893919if (process.platform !== "win32" && child.pid !== undefined) {
894920try {
895921process.kill(-child.pid, signal);
896-return;
922+return true;
897923} catch {
898924// Fall back to the direct child below.
899925}
900926}
901-child.kill(signal);
927+return child.kill(signal);
902928}
903929904930function readProcessRssMb(pid: number | undefined): number | null {
@@ -1197,6 +1223,15 @@ function resolveRestartDeadlineFailure(childExited: boolean): GatewayRestartFail
11971223return childExited ? "restart_child_exited" : "restart_deadline_timeout";
11981224}
119912251226+function resolveSampleExitFailure(exit: StopChildResult): GatewayRestartFailureCode | null {
1227+if (!exit.exitedBeforeTeardown) {
1228+return null;
1229+}
1230+return exit.exitCode !== null && exit.exitCode !== 0
1231+ ? "child_nonzero_exit"
1232+ : "restart_child_exited";
1233+}
1234+12001235function computeResourceSlope(iterations: RestartIteration[]): ResourceSlope {
12011236return {
12021237activeHandlesCountPerRestart: slope(
@@ -1528,9 +1563,7 @@ async function runGatewaySample(options: {
15281563flushOutputLineBuffers(outputBuffers, onLine, performance.now() - sampleStartAt, {
15291564flushPartial: true,
15301565});
1531-if (exit.exitCode !== null && exit.exitCode !== 0 && failureCode === null) {
1532-failureCode = "child_nonzero_exit";
1533-}
1566+failureCode ??= resolveSampleExitFailure(exit);
15341567try {
15351568rmSync(root, { force: true, maxRetries: 3, recursive: true, retryDelay: 100 });
15361569} catch {
@@ -1541,6 +1574,7 @@ async function runGatewaySample(options: {
15411574childExitCode: exit.exitCode,
15421575childSignal: exit.signal,
15431576 events,
1577+exitedBeforeTeardown: exit.exitedBeforeTeardown,
15441578 failureCode,
15451579 firstOutputMs,
15461580 initialGatewayReadyLogLine,
@@ -1693,8 +1727,10 @@ export const testing = {
16931727 resolveRestartDeadlineFailure,
16941728 resolveEntry,
16951729 resolvePhaseDeadlineAt,
1730+ resolveSampleExitFailure,
16961731 sanitizedEnv,
16971732 shouldFailBenchmark,
1733+ stopChild,
16981734 summarizeCase,
16991735 waitForRestartProbe,
17001736 writeConfig,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。