Skip to content

Commit e913e07

Browse files
committed
fix(scripts): clamp openwebui probe timers
1 parent 8e24695 commit e913e07

2 files changed

Lines changed: 35 additions & 13 deletions

File tree

scripts/e2e/openwebui-probe.mjs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ const email = process.env.OPENWEBUI_ADMIN_EMAIL ?? "";
77
const password = process.env.OPENWEBUI_ADMIN_PASSWORD ?? "";
88
const expectedNonce = process.env.OPENWEBUI_EXPECTED_NONCE ?? "";
99
const prompt = process.env.OPENWEBUI_PROMPT ?? "";
10+
const MAX_TIMER_TIMEOUT_MS = 2_147_000_000;
1011
const modelAttempts = readPositiveInt("OPENWEBUI_MODEL_ATTEMPTS", 72);
11-
const modelRetryMs = readNonNegativeInt("OPENWEBUI_MODEL_RETRY_MS", 5000);
12-
const fetchTimeoutMs = readPositiveInt("OPENWEBUI_FETCH_TIMEOUT_MS", 720000);
13-
const controlTimeoutMs = readPositiveInt(
12+
const modelRetryMs = readNonNegativeTimerMs("OPENWEBUI_MODEL_RETRY_MS", 5000);
13+
const fetchTimeoutMs = readPositiveTimerMs("OPENWEBUI_FETCH_TIMEOUT_MS", 720000);
14+
const controlTimeoutMs = readPositiveTimerMs(
1415
"OPENWEBUI_CONTROL_TIMEOUT_MS",
1516
Math.min(fetchTimeoutMs, 30000),
1617
);
17-
const chatTimeoutMs = readPositiveInt("OPENWEBUI_CHAT_TIMEOUT_MS", fetchTimeoutMs);
18+
const chatTimeoutMs = readPositiveTimerMs("OPENWEBUI_CHAT_TIMEOUT_MS", fetchTimeoutMs);
1819
const responseBodyMaxBytes = readPositiveInt("OPENWEBUI_RESPONSE_BODY_MAX_BYTES", 1024 * 1024);
1920
const smokeMode =
2021
process.env.OPENWEBUI_SMOKE_MODE ?? process.env.OPENCLAW_OPENWEBUI_SMOKE_MODE ?? "chat";
@@ -65,21 +66,36 @@ function readNonNegativeInt(name, fallback) {
6566
return parsed;
6667
}
6768

69+
function clampTimerTimeoutMs(valueMs, minMs = 1) {
70+
const min = Math.max(0, Math.floor(minMs));
71+
const value = Number.isFinite(valueMs) ? valueMs : min;
72+
return Math.min(Math.max(Math.floor(value), min), MAX_TIMER_TIMEOUT_MS);
73+
}
74+
75+
function readPositiveTimerMs(name, fallback) {
76+
return clampTimerTimeoutMs(readPositiveInt(name, fallback));
77+
}
78+
79+
function readNonNegativeTimerMs(name, fallback) {
80+
return clampTimerTimeoutMs(readNonNegativeInt(name, fallback), 0);
81+
}
82+
6883
function createTimeoutError(label, timeoutMs) {
6984
const error = new Error(`${label} timed out after ${timeoutMs}ms`);
7085
error.code = "ETIMEDOUT";
7186
return error;
7287
}
7388

7489
async function withRequestTimeout(label, timeoutMs, run) {
90+
const resolvedTimeoutMs = clampTimerTimeoutMs(timeoutMs);
7591
const controller = new AbortController();
76-
const timeoutError = createTimeoutError(label, timeoutMs);
92+
const timeoutError = createTimeoutError(label, resolvedTimeoutMs);
7793
let timer;
7894
const timeoutPromise = new Promise((_, reject) => {
7995
timer = setTimeout(() => {
8096
controller.abort(timeoutError);
8197
reject(timeoutError);
82-
}, timeoutMs);
98+
}, resolvedTimeoutMs);
8399
timer.unref?.();
84100
});
85101
try {
@@ -138,7 +154,7 @@ function buildAuthHeaders(token, cookie) {
138154

139155
function sleep(ms) {
140156
return new Promise((resolve) => {
141-
setTimeout(resolve, ms);
157+
setTimeout(resolve, clampTimerTimeoutMs(ms, 0));
142158
});
143159
}
144160

test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
44
import { createServer, type IncomingMessage, type Server as HttpServer } from "node:http";
55
import { createServer as createTcpServer, type Server as TcpServer, type Socket } from "node:net";
66
import path from "node:path";
7+
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
78
import { describe, expect, it } from "vitest";
89
import { createBoundedChildOutput } from "../../../helpers/bounded-child-output.js";
910

@@ -361,11 +362,13 @@ describe("scripts/e2e/openwebui-probe.mjs", () => {
361362
it("passes in models mode when Open WebUI exposes the OpenClaw model", async () => {
362363
const server = createServer((request, response) => {
363364
if (request.url === "/api/v1/auths/signin") {
364-
response.writeHead(200, {
365-
"content-type": "application/json",
366-
"set-cookie": "openwebui-session=test; Path=/",
367-
});
368-
response.end(JSON.stringify({ token: "test-token" }));
365+
setTimeout(() => {
366+
response.writeHead(200, {
367+
"content-type": "application/json",
368+
"set-cookie": "openwebui-session=test; Path=/",
369+
});
370+
response.end(JSON.stringify({ token: "test-token" }));
371+
}, 25);
369372
return;
370373
}
371374
if (request.url === "/api/models") {
@@ -379,7 +382,10 @@ describe("scripts/e2e/openwebui-probe.mjs", () => {
379382
});
380383
const baseUrl = await listen(server);
381384
try {
382-
const result = await runProbe(baseUrl);
385+
const result = await runProbe(baseUrl, {
386+
OPENWEBUI_CONTROL_TIMEOUT_MS: String(MAX_TIMER_TIMEOUT_MS + 1),
387+
OPENWEBUI_FETCH_TIMEOUT_MS: String(MAX_TIMER_TIMEOUT_MS + 1),
388+
});
383389

384390
expect(result.status).toBe(0);
385391
expect(JSON.parse(result.stdout)).toMatchObject({

0 commit comments

Comments
 (0)