CLI: keep inactive loopback probes fast
This commit is contained in:
parent
cb88feabb7
commit
b2d714b119
@ -587,6 +587,27 @@ describe("gateway-status command", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps inactive local loopback probes on the short timeout in remote mode", async () => {
|
||||||
|
const { runtime } = createRuntimeCapture();
|
||||||
|
probeGateway.mockClear();
|
||||||
|
readBestEffortConfig.mockResolvedValueOnce({
|
||||||
|
gateway: {
|
||||||
|
mode: "remote",
|
||||||
|
auth: { mode: "token", token: "ltok" },
|
||||||
|
remote: {},
|
||||||
|
},
|
||||||
|
} as never);
|
||||||
|
|
||||||
|
await runGatewayStatus(runtime, { timeout: "15000", json: true });
|
||||||
|
|
||||||
|
expect(probeGateway).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
url: "ws://127.0.0.1:18789",
|
||||||
|
timeoutMs: 800,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("skips invalid ssh-auto discovery targets", async () => {
|
it("skips invalid ssh-auto discovery targets", async () => {
|
||||||
const { runtime } = createRuntimeCapture();
|
const { runtime } = createRuntimeCapture();
|
||||||
await withEnvAsync({ USER: "steipete" }, async () => {
|
await withEnvAsync({ USER: "steipete" }, async () => {
|
||||||
|
|||||||
@ -176,7 +176,7 @@ export async function gatewayStatusCommand(
|
|||||||
token: authResolution.token,
|
token: authResolution.token,
|
||||||
password: authResolution.password,
|
password: authResolution.password,
|
||||||
};
|
};
|
||||||
const timeoutMs = resolveProbeBudgetMs(overallTimeoutMs, target.kind);
|
const timeoutMs = resolveProbeBudgetMs(overallTimeoutMs, target);
|
||||||
const probe = await probeGateway({
|
const probe = await probeGateway({
|
||||||
url: target.url,
|
url: target.url,
|
||||||
auth,
|
auth,
|
||||||
|
|||||||
@ -276,13 +276,19 @@ describe("probe reachability classification", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("resolveProbeBudgetMs", () => {
|
describe("resolveProbeBudgetMs", () => {
|
||||||
it("lets local loopback probes use the full caller budget", () => {
|
it("lets active local loopback probes use the full caller budget", () => {
|
||||||
expect(resolveProbeBudgetMs(15_000, "localLoopback")).toBe(15_000);
|
expect(resolveProbeBudgetMs(15_000, { kind: "localLoopback", active: true })).toBe(15_000);
|
||||||
expect(resolveProbeBudgetMs(3_000, "localLoopback")).toBe(3_000);
|
expect(resolveProbeBudgetMs(3_000, { kind: "localLoopback", active: true })).toBe(3_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps inactive local loopback probes on the short cap", () => {
|
||||||
|
expect(resolveProbeBudgetMs(15_000, { kind: "localLoopback", active: false })).toBe(800);
|
||||||
|
expect(resolveProbeBudgetMs(500, { kind: "localLoopback", active: false })).toBe(500);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps non-local probe caps unchanged", () => {
|
it("keeps non-local probe caps unchanged", () => {
|
||||||
expect(resolveProbeBudgetMs(15_000, "configRemote")).toBe(1_500);
|
expect(resolveProbeBudgetMs(15_000, { kind: "configRemote", active: true })).toBe(1_500);
|
||||||
expect(resolveProbeBudgetMs(15_000, "sshTunnel")).toBe(2_000);
|
expect(resolveProbeBudgetMs(15_000, { kind: "explicit", active: true })).toBe(1_500);
|
||||||
|
expect(resolveProbeBudgetMs(15_000, { kind: "sshTunnel", active: true })).toBe(2_000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,6 +13,7 @@ const MISSING_SCOPE_PATTERN = /\bmissing scope:\s*[a-z0-9._-]+/i;
|
|||||||
|
|
||||||
type TargetKind = "explicit" | "configRemote" | "localLoopback" | "sshTunnel";
|
type TargetKind = "explicit" | "configRemote" | "localLoopback" | "sshTunnel";
|
||||||
|
|
||||||
|
const INACTIVE_LOOPBACK_PROBE_BUDGET_MS = 800;
|
||||||
const REMOTE_PROBE_BUDGET_MS = 1_500;
|
const REMOTE_PROBE_BUDGET_MS = 1_500;
|
||||||
const SSH_TUNNEL_PROBE_BUDGET_MS = 2_000;
|
const SSH_TUNNEL_PROBE_BUDGET_MS = 2_000;
|
||||||
|
|
||||||
@ -119,12 +120,16 @@ export function resolveTargets(cfg: OpenClawConfig, explicitUrl?: string): Gatew
|
|||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveProbeBudgetMs(overallMs: number, kind: TargetKind): number {
|
export function resolveProbeBudgetMs(
|
||||||
switch (kind) {
|
overallMs: number,
|
||||||
|
target: Pick<GatewayStatusTarget, "kind" | "active">,
|
||||||
|
): number {
|
||||||
|
switch (target.kind) {
|
||||||
case "localLoopback":
|
case "localLoopback":
|
||||||
// Let the local probe use the caller's full budget. Slow local shells/containers can
|
// Active loopback probes should honor the caller budget because local shells/containers
|
||||||
// exceed the old fixed cap and produce false "unreachable" results.
|
// can legitimately take longer to connect. Inactive loopback probes stay bounded so
|
||||||
return overallMs;
|
// remote-mode status checks do not stall on an expected local miss.
|
||||||
|
return target.active ? overallMs : Math.min(INACTIVE_LOOPBACK_PROBE_BUDGET_MS, overallMs);
|
||||||
case "sshTunnel":
|
case "sshTunnel":
|
||||||
return Math.min(SSH_TUNNEL_PROBE_BUDGET_MS, overallMs);
|
return Math.min(SSH_TUNNEL_PROBE_BUDGET_MS, overallMs);
|
||||||
default:
|
default:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user