




























@@ -50,7 +50,8 @@ const abortEmbeddedPiRun = vi.fn(
5050const getActiveEmbeddedRunCount = vi.fn(() => 0);
5151const waitForActiveEmbeddedRuns = vi.fn(async (_timeoutMs?: number) => ({ drained: true }));
5252const DRAIN_TIMEOUT_LOG = "drain timeout reached; proceeding with restart";
53-const loadConfig = vi.fn(() => ({
53+const DEFAULT_RESTART_DEFERRAL_TIMEOUT_MS = 300_000;
54+const loadConfig = vi.fn<() => { gateway: { reload: { deferralTimeoutMs?: number } } }>(() => ({
5455gateway: {
5556reload: {
5657deferralTimeoutMs: 90_000,
@@ -74,6 +75,15 @@ vi.mock("../../infra/restart.js", () => ({
7475markGatewaySigusr1RestartHandled: () => markGatewaySigusr1RestartHandled(),
7576peekGatewaySigusr1RestartReason: () => peekGatewaySigusr1RestartReason(),
7677resetGatewayRestartStateForInProcessRestart: () => resetGatewayRestartStateForInProcessRestart(),
78+resolveGatewayRestartDeferralTimeoutMs: (timeoutMs: unknown) => {
79+if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs)) {
80+return DEFAULT_RESTART_DEFERRAL_TIMEOUT_MS;
81+}
82+if (timeoutMs <= 0) {
83+return undefined;
84+}
85+return Math.floor(timeoutMs);
86+},
7787scheduleGatewaySigusr1Restart: (opts?: { delayMs?: number; reason?: string }) =>
7888scheduleGatewaySigusr1Restart(opts),
7989}));
@@ -438,6 +448,31 @@ describe("runGatewayLoop", () => {
438448});
439449});
440450451+it("uses the default restart drain timeout when config omits deferralTimeoutMs", async () => {
452+vi.clearAllMocks();
453+loadConfig.mockReturnValue({ gateway: { reload: {} } });
454+peekGatewaySigusr1RestartReason.mockReturnValue(undefined);
455+respawnGatewayProcessForUpdate.mockReturnValue({
456+mode: "disabled",
457+detail: "OPENCLAW_NO_RESPAWN",
458+});
459+460+await withIsolatedSignals(async ({ captureSignal }) => {
461+getActiveTaskCount.mockReturnValueOnce(1).mockReturnValue(0);
462+463+const { start } = await createSignaledLoopHarness();
464+const sigusr1 = captureSignal("SIGUSR1");
465+466+sigusr1();
467+await new Promise<void>((resolve) => setImmediate(resolve));
468+await new Promise<void>((resolve) => setImmediate(resolve));
469+470+expect(waitForActiveTasks).toHaveBeenCalledWith(DEFAULT_RESTART_DEFERRAL_TIMEOUT_MS);
471+expect(markGatewayDraining).toHaveBeenCalledOnce();
472+expect(start).toHaveBeenCalledTimes(2);
473+});
474+});
475+441476it("routes external SIGUSR1 through the restart scheduler before draining", async () => {
442477vi.clearAllMocks();
443478consumeGatewaySigusr1RestartAuthorization.mockReturnValueOnce(false);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。