fix(channels): centralize stall watchdog timer bounds · openclaw/openclaw@d7354d6
steipete
·
2026-05-30
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
1 | 2 | import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; |
2 | 3 | import { createMattermostClient, createMattermostDirectChannelWithRetry } from "./client.js"; |
3 | 4 | |
4 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
5 | | - |
6 | 5 | describe("createMattermostDirectChannelWithRetry", () => { |
7 | 6 | const mockFetch = vi.fn<typeof fetch>(); |
8 | 7 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
1 | 2 | import { afterEach, describe, expect, it, vi } from "vitest"; |
2 | 3 | import { requestMatrixJson, type MatrixQaFetchLike } from "./request.js"; |
3 | 4 | |
4 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
5 | | - |
6 | 5 | describe("requestMatrixJson", () => { |
7 | 6 | afterEach(() => { |
8 | 7 | vi.restoreAllMocks(); |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | import { Buffer } from "node:buffer"; |
2 | 2 | import { once } from "node:events"; |
3 | 3 | import http, { type IncomingMessage, type ServerResponse } from "node:http"; |
| 4 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
4 | 5 | import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; |
5 | 6 | |
6 | 7 | vi.mock("openclaw/plugin-sdk/core", async () => { |
@@ -17,8 +18,6 @@ let signalCheck: typeof import("./client.js").signalCheck;
|
17 | 18 | let signalRpcRequest: typeof import("./client.js").signalRpcRequest; |
18 | 19 | let streamSignalEvents: typeof import("./client.js").streamSignalEvents; |
19 | 20 | |
20 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
21 | | - |
22 | 21 | const servers: http.Server[] = []; |
23 | 22 | |
24 | 23 | async function readRequestBody(req: IncomingMessage): Promise<string> { |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
1 | 2 | import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; |
2 | 3 | |
3 | 4 | const transcodeAudioBufferToOpusMock = vi.hoisted(() => vi.fn()); |
@@ -8,8 +9,6 @@ vi.mock("openclaw/plugin-sdk/media-runtime", () => ({
|
8 | 9 | |
9 | 10 | import { buildXiaomiSpeechProvider } from "./speech-provider.js"; |
10 | 11 | |
11 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
12 | | - |
13 | 12 | describe("buildXiaomiSpeechProvider", () => { |
14 | 13 | const provider = buildXiaomiSpeechProvider(); |
15 | 14 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
1 | 2 | import { afterEach, describe, expect, it, vi } from "vitest"; |
2 | 3 | import { detectZaiEndpoint } from "./detect.js"; |
3 | 4 | |
4 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
5 | | - |
6 | 5 | type FetchResponse = { status: number; body?: unknown }; |
7 | 6 | |
8 | 7 | function makeFetch(map: Record<string, FetchResponse>) { |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
1 | 2 | import { beforeEach, describe, expect, it, vi } from "vitest"; |
2 | 3 | |
3 | 4 | const { resolvePinnedHostnameWithPolicyMock } = vi.hoisted(() => ({ |
@@ -11,8 +12,6 @@ vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
|
11 | 12 | |
12 | 13 | import { deleteWebhook, getWebhookInfo, sendChatAction, sendPhoto, type ZaloFetch } from "./api.js"; |
13 | 14 | |
14 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
15 | | - |
16 | 15 | function createOkFetcher() { |
17 | 16 | return vi.fn<ZaloFetch>(async () => new Response(JSON.stringify({ ok: true, result: {} }))); |
18 | 17 | } |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | import { afterEach, describe, expect, it, vi } from "vitest"; |
| 2 | +import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js"; |
2 | 3 | import { withEnvAsync } from "../test-utils/env.js"; |
3 | 4 | import { withFetchPreconnect } from "../test-utils/fetch-mock.js"; |
4 | 5 | import { scanOpenRouterModels } from "./model-scan.js"; |
5 | 6 | |
6 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
7 | | - |
8 | 7 | function createFetchFixture(payload: unknown): typeof fetch { |
9 | 8 | return withFetchPreconnect( |
10 | 9 | async () => |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | import { describe, expect, it, vi } from "vitest"; |
| 2 | +import { MAX_TIMER_TIMEOUT_MS } from "../../shared/number-coercion.js"; |
2 | 3 | import { createArmableStallWatchdog } from "./stall-watchdog.js"; |
3 | 4 | |
4 | 5 | function createTestWatchdog( |
@@ -67,4 +68,29 @@ describe("createArmableStallWatchdog", () => {
|
67 | 68 | vi.useRealTimers(); |
68 | 69 | } |
69 | 70 | }); |
| 71 | + |
| 72 | +it("caps oversized timeout and check interval values before scheduling", async () => { |
| 73 | +vi.useFakeTimers(); |
| 74 | +vi.setSystemTime(0); |
| 75 | +try { |
| 76 | +const onTimeout = vi.fn(); |
| 77 | +const intervalSpy = vi.spyOn(globalThis, "setInterval"); |
| 78 | +const watchdog = createArmableStallWatchdog({ |
| 79 | +label: "test-watchdog", |
| 80 | +timeoutMs: Number.MAX_SAFE_INTEGER, |
| 81 | +checkIntervalMs: Number.MAX_SAFE_INTEGER, |
| 82 | + onTimeout, |
| 83 | +}); |
| 84 | + |
| 85 | +watchdog.arm(0); |
| 86 | +await vi.advanceTimersByTimeAsync(1); |
| 87 | + |
| 88 | +expect(onTimeout).not.toHaveBeenCalled(); |
| 89 | +expect(intervalSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS); |
| 90 | +watchdog.stop(); |
| 91 | +} finally { |
| 92 | +vi.useRealTimers(); |
| 93 | +vi.restoreAllMocks(); |
| 94 | +} |
| 95 | +}); |
70 | 96 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | import type { RuntimeEnv } from "../../runtime.js"; |
| 2 | +import { resolveTimerTimeoutMs } from "../../shared/number-coercion.js"; |
2 | 3 | |
3 | 4 | export type StallWatchdogTimeoutMeta = { |
4 | 5 | idleMs: number; |
@@ -21,10 +22,12 @@ export function createArmableStallWatchdog(params: {
|
21 | 22 | runtime?: RuntimeEnv; |
22 | 23 | onTimeout: (meta: StallWatchdogTimeoutMeta) => void; |
23 | 24 | }): ArmableStallWatchdog { |
24 | | -const timeoutMs = Math.max(1, Math.floor(params.timeoutMs)); |
25 | | -const checkIntervalMs = Math.max( |
| 25 | +const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 1); |
| 26 | +const defaultCheckIntervalMs = Math.min(5_000, Math.max(250, timeoutMs / 6)); |
| 27 | +const checkIntervalMs = resolveTimerTimeoutMs( |
| 28 | +params.checkIntervalMs, |
| 29 | +defaultCheckIntervalMs, |
26 | 30 | 100, |
27 | | -Math.floor(params.checkIntervalMs ?? Math.min(5_000, Math.max(250, timeoutMs / 6))), |
28 | 31 | ); |
29 | 32 | |
30 | 33 | let armed = false; |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | import { afterEach, describe, expect, it, vi } from "vitest"; |
| 2 | +import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js"; |
2 | 3 | import { probeGatewayUrl, probeLocalCommand } from "./probes.js"; |
3 | 4 | |
4 | | -const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
5 | | - |
6 | 5 | describe("crestodian probes", () => { |
7 | 6 | afterEach(() => { |
8 | 7 | vi.restoreAllMocks(); |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。