
























@@ -10,6 +10,7 @@ import { createLazyImportLoader } from "../../shared/lazy-promise.js";
1010const gatewayLog = createSubsystemLogger("gateway");
1111const LAUNCHD_SUPERVISED_RESTART_EXIT_DELAY_MS = 1500;
1212const DEFAULT_RESTART_DRAIN_TIMEOUT_MS = 300_000;
13+const RESTART_ACTIVE_EMBEDDED_RUN_ABORT_GRACE_MS = 30_000;
1314const RESTART_DRAIN_STILL_PENDING_WARN_MS = 30_000;
1415const UPDATE_RESPAWN_HEALTH_TIMEOUT_MS = 10_000;
1516const UPDATE_RESPAWN_HEALTH_POLL_MS = 200;
@@ -345,6 +346,15 @@ export async function runGatewayLoop(params: {
345346restartDrainTimeoutMs === undefined
346347 ? "without a timeout"
347348 : `with timeout ${restartDrainTimeoutMs}ms`;
349+const resolveActiveRunDrainWaitMs = (activeRuns: number): RestartDrainTimeoutMs => {
350+if (activeRuns <= 0) {
351+return restartDrainTimeoutMs;
352+}
353+if (restartDrainTimeoutMs === undefined) {
354+return RESTART_ACTIVE_EMBEDDED_RUN_ABORT_GRACE_MS;
355+}
356+return Math.min(restartDrainTimeoutMs, RESTART_ACTIVE_EMBEDDED_RUN_ABORT_GRACE_MS);
357+};
348358const armCloseForceExitTimerForIndefiniteRestart = () => {
349359if (isRestart && restartDrainTimeoutMs === undefined) {
350360armForceExitTimer(SHUTDOWN_TIMEOUT_MS);
@@ -417,22 +427,40 @@ export async function runGatewayLoop(params: {
417427gatewayLog.warn("forced restart requested; skipping active work drain");
418428abortEmbeddedPiRun(undefined, { mode: "all" });
419429} else {
430+const activeRunDrainWaitMs = resolveActiveRunDrainWaitMs(activeRuns);
420431const stillPendingDrainLogger = createStillPendingDrainLogger();
421-const [tasksDrain, runsDrain] = await Promise.all([
422-activeTasks > 0
423- ? waitForActiveTasks(restartDrainTimeoutMs)
424- : Promise.resolve({ drained: true }),
425-activeRuns > 0
426- ? waitForActiveEmbeddedRuns(restartDrainTimeoutMs)
427- : Promise.resolve({ drained: true }),
428-]).finally(() => clearInterval(stillPendingDrainLogger));
432+let abortedAfterRunGrace = false;
433+let tasksDrain: { drained: boolean } = { drained: true };
434+let runsDrain: { drained: boolean } = { drained: true };
435+try {
436+const tasksDrainPromise =
437+activeTasks > 0
438+ ? waitForActiveTasks(restartDrainTimeoutMs)
439+ : Promise.resolve({ drained: true });
440+runsDrain =
441+activeRuns > 0
442+ ? await waitForActiveEmbeddedRuns(activeRunDrainWaitMs)
443+ : { drained: true };
444+if (!runsDrain.drained && activeRuns > 0) {
445+gatewayLog.warn(
446+"active embedded run drain grace reached; aborting active run(s) before restart",
447+);
448+abortEmbeddedPiRun(undefined, { mode: "all" });
449+abortedAfterRunGrace = true;
450+}
451+tasksDrain = await tasksDrainPromise;
452+} finally {
453+clearInterval(stillPendingDrainLogger);
454+}
429455if (tasksDrain.drained && runsDrain.drained) {
430456gatewayLog.info("all active work drained");
431457} else {
432458gatewayLog.warn("drain timeout reached; proceeding with restart");
433459// Final best-effort abort to avoid carrying active runs into the
434460// next lifecycle when drain time budget is exhausted.
435-abortEmbeddedPiRun(undefined, { mode: "all" });
461+if (!abortedAfterRunGrace) {
462+abortEmbeddedPiRun(undefined, { mode: "all" });
463+}
436464}
437465}
438466}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。