fix(gateway): clamp lock poll timers

This commit is contained in:
Peter Steinberger
2026-05-30 17:31:00 -04:00
parent 37fbc8cd8f
commit 1670b970ee
2 changed files with 43 additions and 5 deletions

View File

@@ -293,6 +293,33 @@ describe("gateway lock", () => {
}
});
it("bounds oversized lock polling intervals by the acquire timeout", async () => {
const env = await makeEnv();
await writeRecentLockFile(env);
const sleepDelays: number[] = [];
let now = 0;
await expect(
acquireGatewayLock({
env,
allowInTests: true,
timeoutMs: 5,
pollIntervalMs: Number.MAX_SAFE_INTEGER,
staleMs: 10_000,
platform: "darwin",
now: () => now,
sleep: async (ms) => {
sleepDelays.push(ms);
now = 10;
},
lockDir: resolveTestLockDir(),
readProcessCmdline: () => ["/usr/local/bin/openclaw", "gateway", "run"],
}),
).rejects.toBeInstanceOf(GatewayLockError);
expect(sleepDelays).toEqual([5]);
});
it("returns null when multi-gateway override is enabled", async () => {
const env = await makeEnv();
const lock = await acquireGatewayLock({

View File

@@ -4,7 +4,11 @@ import fsSync from "node:fs";
import fs from "node:fs/promises";
import net from "node:net";
import path from "node:path";
import { resolveTimestampMsToIsoString } from "@openclaw/normalization-core/number-coercion";
import {
resolvePositiveTimerTimeoutMs,
resolveTimerTimeoutMs,
resolveTimestampMsToIsoString,
} from "@openclaw/normalization-core/number-coercion";
import { z } from "zod";
import { resolveConfigPath, resolveGatewayLockDir, resolveStateDir } from "../config/paths.js";
import { isPidAlive } from "../shared/pid-alive.js";
@@ -256,9 +260,12 @@ export async function acquireGatewayLock(
return null;
}
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
const pollIntervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
const staleMs = opts.staleMs ?? DEFAULT_STALE_MS;
const timeoutMs = resolveTimerTimeoutMs(opts.timeoutMs, DEFAULT_TIMEOUT_MS, 0);
const pollIntervalMs = resolvePositiveTimerTimeoutMs(
opts.pollIntervalMs,
DEFAULT_POLL_INTERVAL_MS,
);
const staleMs = resolveTimerTimeoutMs(opts.staleMs, DEFAULT_STALE_MS, 0);
const platform = opts.platform ?? process.platform;
const port = opts.port;
const now = opts.now ?? Date.now;
@@ -336,7 +343,11 @@ export async function acquireGatewayLock(
}
}
await sleep(pollIntervalMs);
const remainingMs = timeoutMs - (now() - startedAt);
if (remainingMs <= 0) {
break;
}
await sleep(Math.min(pollIntervalMs, remainingMs));
}
}