Merge pull request #918 from rdself/coder/fix-timeout-env-stream-300s

fix: make request and stream timeouts fully env-configurable
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-04-02 14:36:53 -03:00
committed by GitHub
10 changed files with 404 additions and 33 deletions

View File

@@ -189,10 +189,21 @@ GEMINI_CLI_USER_AGENT=google-api-nodejs-client/9.15.1
# Provider keys above (openai, mistral, together, fireworks, nvidia) also work for embeddings
# Timeout settings
# FETCH_TIMEOUT_MS=120000
# STREAM_IDLE_TIMEOUT_MS=60000
# REQUEST_TIMEOUT_MS=600000
# STREAM_IDLE_TIMEOUT_MS=600000
# Advanced timeout overrides (optional)
# FETCH_TIMEOUT_MS=600000
# FETCH_HEADERS_TIMEOUT_MS=600000
# FETCH_BODY_TIMEOUT_MS=600000
# FETCH_CONNECT_TIMEOUT_MS=30000
# FETCH_KEEPALIVE_TIMEOUT_MS=4000
# TLS_CLIENT_TIMEOUT_MS=600000
# API bridge timeout for /v1 proxy requests (default: 30000)
# API_BRIDGE_PROXY_TIMEOUT_MS=120000
# API_BRIDGE_PROXY_TIMEOUT_MS=600000
# API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS=600000
# API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS=60000
# API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS=5000
# API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS=0
# CORS configuration (default: * allows all origins)
# CORS_ORIGINS=*

View File

@@ -803,6 +803,36 @@ PORT=20128 DASHBOARD_PORT=20129 omniroute
# Dashboard: http://localhost:20129
```
### Long-Running Streaming Timeouts
For most deployments, you only need:
| Variable | Default | Purpose |
| ------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `REQUEST_TIMEOUT_MS` | `600000` | Shared baseline for upstream fetch, hidden Undici timeouts, TLS fingerprint requests, and API bridge request/proxy timeouts |
| `STREAM_IDLE_TIMEOUT_MS` | inherits `REQUEST_TIMEOUT_MS` | Maximum gap between streaming chunks before OmniRoute aborts the SSE stream |
Backward compatibility is preserved: existing `FETCH_TIMEOUT_MS`, `API_BRIDGE_PROXY_TIMEOUT_MS`, and other per-layer timeout vars still work and override the shared baseline.
Advanced overrides are available if you need finer control:
| Variable | Default | Purpose |
| ---------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------- |
| `FETCH_TIMEOUT_MS` | inherits `REQUEST_TIMEOUT_MS` | Total upstream request timeout used by the main fetch abort signal |
| `FETCH_HEADERS_TIMEOUT_MS` | inherits `FETCH_TIMEOUT_MS` | Undici time limit for receiving upstream response headers |
| `FETCH_BODY_TIMEOUT_MS` | inherits `FETCH_TIMEOUT_MS` | Undici time limit between upstream body chunks (`0` disables it) |
| `FETCH_CONNECT_TIMEOUT_MS` | `30000` | Undici TCP connect timeout |
| `FETCH_KEEPALIVE_TIMEOUT_MS` | `4000` | Undici idle keep-alive socket timeout |
| `TLS_CLIENT_TIMEOUT_MS` | inherits `FETCH_TIMEOUT_MS` | Timeout for TLS fingerprint requests made through `wreq-js` |
| `API_BRIDGE_PROXY_TIMEOUT_MS` | inherits `REQUEST_TIMEOUT_MS` or `30000` | Timeout for `/v1` proxy forwarding from API port to dashboard port |
| `API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS` | `max(API_BRIDGE_PROXY_TIMEOUT_MS, 300000)` | Incoming request timeout on the API bridge server |
| `API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS` | `60000` | Incoming header timeout on the API bridge server |
| `API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS` | `5000` | Keep-alive timeout on the API bridge server |
| `API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS` | `0` | Socket inactivity timeout on the API bridge server (`0` disables it) |
If you run OmniRoute behind Nginx, Caddy, Cloudflare, or another reverse proxy, make sure the proxy
timeouts are also higher than your OmniRoute stream/fetch timeouts.
### 2) Connect providers and create your API key
1. Open Dashboard → `Providers` and connect at least one provider (OAuth or API key).

View File

@@ -213,8 +213,8 @@ server {
# SSE (Server-Sent Events) — streaming AI responses
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
@@ -228,6 +228,10 @@ server {
NGINX
```
Keep reverse-proxy stream timeouts aligned with your OmniRoute timeout env vars. If you raise
`FETCH_TIMEOUT_MS` / `STREAM_IDLE_TIMEOUT_MS`, raise `proxy_read_timeout` / `proxy_send_timeout`
above the same threshold.
### 3.3 Enable and Test
```bash

View File

@@ -1,18 +1,22 @@
import { getUpstreamTimeoutConfig } from "@/shared/utils/runtimeTimeouts";
import { loadProviderCredentials } from "./credentialLoader.ts";
import { generateLegacyProviders } from "./providerRegistry.ts";
const upstreamTimeouts = getUpstreamTimeoutConfig(process.env, (message) => {
console.warn(`[open-sse] ${message}`);
});
// Timeout for non-streaming fetch requests (ms). Prevents stalled connections.
export const FETCH_TIMEOUT_MS = parseInt(process.env.FETCH_TIMEOUT_MS || "600000", 10);
export const FETCH_TIMEOUT_MS = upstreamTimeouts.fetchTimeoutMs;
// Idle timeout for SSE streams (ms). Closes stream if no data for this duration.
// Default: 120s balances deep-reasoning pauses with fast zombie stream detection (#473).
// Extended-thinking models rarely pause >90s between chunks. Override with STREAM_IDLE_TIMEOUT_MS env var.
export const STREAM_IDLE_TIMEOUT_MS = parseInt(process.env.STREAM_IDLE_TIMEOUT_MS || "600000", 10);
export const STREAM_IDLE_TIMEOUT_MS = upstreamTimeouts.streamIdleTimeoutMs;
// Provider configurations
// OAuth credentials read from env vars with hardcoded fallbacks for backward compatibility.
// Use provider-credentials.json or env vars to override in production.
import { generateLegacyProviders } from "./providerRegistry.ts";
export const PROVIDERS = generateLegacyProviders();
// Merge external credentials from data/provider-credentials.json (if present)

View File

@@ -1,12 +1,15 @@
import { ProxyAgent, type Dispatcher } from "undici";
import { Agent, ProxyAgent, type Dispatcher } from "undici";
import { socksDispatcher } from "fetch-socks";
import { getUpstreamTimeoutConfig } from "@/shared/utils/runtimeTimeouts";
const DISPATCHER_CACHE_KEY = Symbol.for("omniroute.proxyDispatcher.cache");
const DEFAULT_DISPATCHER_KEY = Symbol.for("omniroute.proxyDispatcher.default");
const SUPPORTED_PROTOCOLS = new Set(["http:", "https:", "socks5:"]);
type DispatcherCache = Map<string, Dispatcher>;
type GlobalWithDispatcherCache = typeof globalThis & {
[DISPATCHER_CACHE_KEY]?: DispatcherCache;
[DEFAULT_DISPATCHER_KEY]?: Dispatcher;
};
type SocksDispatcherOptions = {
type: number;
@@ -38,6 +41,30 @@ function getDispatcherCache(): DispatcherCache {
export function clearDispatcherCache() {
const cache = getDispatcherCache();
cache.clear();
const globalWithCache = globalThis as GlobalWithDispatcherCache;
delete globalWithCache[DEFAULT_DISPATCHER_KEY];
}
function getDispatcherOptions() {
const timeouts = getUpstreamTimeoutConfig(process.env, (message) => {
console.warn(`[ProxyDispatcher] ${message}`);
});
return {
headersTimeout: timeouts.fetchHeadersTimeoutMs,
bodyTimeout: timeouts.fetchBodyTimeoutMs,
connectTimeout: timeouts.fetchConnectTimeoutMs,
keepAliveTimeout: timeouts.fetchKeepAliveTimeoutMs,
};
}
export function getDefaultDispatcher(): Dispatcher {
const globalWithCache = globalThis as GlobalWithDispatcherCache;
if (!globalWithCache[DEFAULT_DISPATCHER_KEY]) {
globalWithCache[DEFAULT_DISPATCHER_KEY] = new Agent(getDispatcherOptions());
}
return globalWithCache[DEFAULT_DISPATCHER_KEY];
}
/**
@@ -180,6 +207,7 @@ export function proxyConfigToUrl(
export function createProxyDispatcher(proxyUrl: string): Dispatcher {
const normalizedUrl = normalizeProxyUrl(proxyUrl, "proxy dispatcher");
const dispatcherCache = getDispatcherCache();
const dispatcherOptions = getDispatcherOptions();
let dispatcher = dispatcherCache.get(normalizedUrl);
if (dispatcher) return dispatcher;
@@ -197,10 +225,14 @@ export function createProxyDispatcher(proxyUrl: string): Dispatcher {
if (parsed.username) socksOptions.userId = decodeURIComponent(parsed.username);
if (parsed.password) socksOptions.password = decodeURIComponent(parsed.password);
dispatcher = socksDispatcher(
socksOptions as Parameters<typeof socksDispatcher>[0]
socksOptions as Parameters<typeof socksDispatcher>[0],
dispatcherOptions
) as Dispatcher;
} else {
dispatcher = new ProxyAgent(normalizedUrl);
dispatcher = new ProxyAgent({
uri: normalizedUrl,
...dispatcherOptions,
});
}
dispatcherCache.set(normalizedUrl, dispatcher);

View File

@@ -1,6 +1,7 @@
import { AsyncLocalStorage } from "node:async_hooks";
import {
createProxyDispatcher,
getDefaultDispatcher,
normalizeProxyUrl,
proxyConfigToUrl,
proxyUrlForLogs,
@@ -196,7 +197,10 @@ async function patchedFetch(input: RequestInfo | URL, options: FetchWithDispatch
if (store) store.used = false;
}
}
return originalFetchWithDispatcher(input, options);
return originalFetchWithDispatcher(input, {
...options,
dispatcher: getDefaultDispatcher(),
});
}
try {

View File

@@ -1,4 +1,5 @@
import { createRequire } from "module";
import { getTlsClientTimeoutConfig } from "@/shared/utils/runtimeTimeouts";
const require = createRequire(import.meta.url);
@@ -102,6 +103,9 @@ class TlsClient {
async fetch(url: string, options: FetchOptions = {}) {
const session = await this.getSession();
if (!session) throw new Error("wreq-js not available");
const { timeoutMs } = getTlsClientTimeoutConfig(process.env, (message) => {
console.warn(`[TlsClient] ${message}`);
});
const method = (options.method || "GET").toUpperCase();
@@ -110,6 +114,7 @@ class TlsClient {
headers: normalizeHeaders(options.headers),
body: options.body,
redirect: options.redirect === "manual" ? "manual" : "follow",
timeout: timeoutMs,
};
// Pass signal through if available
@@ -129,4 +134,6 @@ class TlsClient {
}
}
export default new TlsClient();
const tlsClient = new TlsClient();
export default tlsClient;

View File

@@ -1,24 +1,11 @@
import http from "http";
import type { IncomingMessage, ServerResponse } from "http";
import { getRuntimePorts } from "@/lib/runtime/ports";
import { getApiBridgeTimeoutConfig } from "@/shared/utils/runtimeTimeouts";
const DEFAULT_PROXY_TIMEOUT_MS = 30_000;
function parseProxyTimeoutMs(raw: string | undefined): number {
if (raw == null || raw.trim() === "") return DEFAULT_PROXY_TIMEOUT_MS;
const parsed = Number(raw);
if (!Number.isFinite(parsed) || parsed <= 0) {
console.warn(
`[API Bridge] Invalid API_BRIDGE_PROXY_TIMEOUT_MS=\"${raw}\". Using default ${DEFAULT_PROXY_TIMEOUT_MS}ms.`
);
return DEFAULT_PROXY_TIMEOUT_MS;
}
return Math.floor(parsed);
}
const PROXY_TIMEOUT_MS = parseProxyTimeoutMs(process.env.API_BRIDGE_PROXY_TIMEOUT_MS);
const API_BRIDGE_TIMEOUTS = getApiBridgeTimeoutConfig(process.env, (message) => {
console.warn(`[API Bridge] ${message}`);
});
const OPENAI_COMPAT_PATHS = [
/^\/v1(?:\/|$)/,
@@ -45,7 +32,7 @@ function proxyRequest(req: IncomingMessage, res: ServerResponse, dashboardPort:
...req.headers,
host: `127.0.0.1:${dashboardPort}`,
},
timeout: PROXY_TIMEOUT_MS,
timeout: API_BRIDGE_TIMEOUTS.proxyTimeoutMs,
},
(targetRes) => {
res.writeHead(targetRes.statusCode || 502, targetRes.headers);
@@ -60,7 +47,7 @@ function proxyRequest(req: IncomingMessage, res: ServerResponse, dashboardPort:
res.end(
JSON.stringify({
error: "api_bridge_timeout",
detail: `Proxy request timed out after ${PROXY_TIMEOUT_MS}ms`,
detail: `Proxy request timed out after ${API_BRIDGE_TIMEOUTS.proxyTimeoutMs}ms`,
})
);
});
@@ -112,6 +99,10 @@ export function initApiBridgeServer(): void {
proxyRequest(req, res, dashboardPort);
});
server.requestTimeout = API_BRIDGE_TIMEOUTS.serverRequestTimeoutMs;
server.headersTimeout = API_BRIDGE_TIMEOUTS.serverHeadersTimeoutMs;
server.keepAliveTimeout = API_BRIDGE_TIMEOUTS.serverKeepAliveTimeoutMs;
server.setTimeout(API_BRIDGE_TIMEOUTS.serverSocketTimeoutMs);
server.on("error", (error: NodeJS.ErrnoException) => {
if (error?.code === "EADDRINUSE") {

View File

@@ -0,0 +1,208 @@
type EnvSource = Record<string, string | undefined>;
type TimeoutLogger = (message: string) => void;
type ReadTimeoutOptions = {
allowZero?: boolean;
logger?: TimeoutLogger;
};
export const DEFAULT_FETCH_TIMEOUT_MS = 600_000;
export const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 600_000;
export const DEFAULT_FETCH_CONNECT_TIMEOUT_MS = 30_000;
export const DEFAULT_FETCH_KEEPALIVE_TIMEOUT_MS = 4_000;
export const DEFAULT_API_BRIDGE_PROXY_TIMEOUT_MS = 30_000;
export const DEFAULT_API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS = 300_000;
export const DEFAULT_API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS = 60_000;
export const DEFAULT_API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS = 5_000;
export const DEFAULT_API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS = 0;
function hasEnvValue(env: EnvSource, name: string): boolean {
const raw = env[name];
return raw != null && raw.trim() !== "";
}
export type UpstreamTimeoutConfig = {
fetchTimeoutMs: number;
streamIdleTimeoutMs: number;
fetchHeadersTimeoutMs: number;
fetchBodyTimeoutMs: number;
fetchConnectTimeoutMs: number;
fetchKeepAliveTimeoutMs: number;
};
export type TlsClientTimeoutConfig = {
timeoutMs: number;
};
export type ApiBridgeTimeoutConfig = {
proxyTimeoutMs: number;
serverRequestTimeoutMs: number;
serverHeadersTimeoutMs: number;
serverKeepAliveTimeoutMs: number;
serverSocketTimeoutMs: number;
};
function readTimeoutMs(
env: EnvSource,
name: string,
defaultValue: number,
options: ReadTimeoutOptions = {}
): number {
const raw = env[name];
if (raw == null || raw.trim() === "") return defaultValue;
const parsed = Number(raw);
const isValid = Number.isFinite(parsed) && (options.allowZero ? parsed >= 0 : parsed > 0);
if (!isValid) {
options.logger?.(`Invalid ${name}="${raw}". Using default ${defaultValue}ms.`);
return defaultValue;
}
return Math.floor(parsed);
}
export function getUpstreamTimeoutConfig(
env: EnvSource = process.env,
logger?: TimeoutLogger
): UpstreamTimeoutConfig {
const sharedRequestTimeoutMs = hasEnvValue(env, "REQUEST_TIMEOUT_MS")
? readTimeoutMs(env, "REQUEST_TIMEOUT_MS", DEFAULT_FETCH_TIMEOUT_MS, {
allowZero: true,
logger,
})
: undefined;
const fetchTimeoutMs = readTimeoutMs(
env,
"FETCH_TIMEOUT_MS",
sharedRequestTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS,
{
allowZero: true,
logger,
}
);
const streamIdleTimeoutMs = readTimeoutMs(
env,
"STREAM_IDLE_TIMEOUT_MS",
sharedRequestTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,
{
allowZero: true,
logger,
}
);
return {
fetchTimeoutMs,
streamIdleTimeoutMs,
fetchHeadersTimeoutMs: readTimeoutMs(env, "FETCH_HEADERS_TIMEOUT_MS", fetchTimeoutMs, {
allowZero: true,
logger,
}),
fetchBodyTimeoutMs: readTimeoutMs(env, "FETCH_BODY_TIMEOUT_MS", fetchTimeoutMs, {
allowZero: true,
logger,
}),
fetchConnectTimeoutMs: readTimeoutMs(
env,
"FETCH_CONNECT_TIMEOUT_MS",
DEFAULT_FETCH_CONNECT_TIMEOUT_MS,
{
allowZero: true,
logger,
}
),
fetchKeepAliveTimeoutMs: readTimeoutMs(
env,
"FETCH_KEEPALIVE_TIMEOUT_MS",
DEFAULT_FETCH_KEEPALIVE_TIMEOUT_MS,
{
logger,
}
),
};
}
export function getTlsClientTimeoutConfig(
env: EnvSource = process.env,
logger?: TimeoutLogger
): TlsClientTimeoutConfig {
const upstream = getUpstreamTimeoutConfig(env, logger);
return {
timeoutMs: readTimeoutMs(env, "TLS_CLIENT_TIMEOUT_MS", upstream.fetchTimeoutMs, {
allowZero: true,
logger,
}),
};
}
export function getApiBridgeTimeoutConfig(
env: EnvSource = process.env,
logger?: TimeoutLogger
): ApiBridgeTimeoutConfig {
const sharedRequestTimeoutMs = hasEnvValue(env, "REQUEST_TIMEOUT_MS")
? readTimeoutMs(env, "REQUEST_TIMEOUT_MS", DEFAULT_FETCH_TIMEOUT_MS, {
allowZero: true,
logger,
})
: undefined;
const proxyTimeoutMs = readTimeoutMs(
env,
"API_BRIDGE_PROXY_TIMEOUT_MS",
sharedRequestTimeoutMs ?? DEFAULT_API_BRIDGE_PROXY_TIMEOUT_MS,
{
allowZero: true,
logger,
}
);
const derivedRequestTimeoutMs =
proxyTimeoutMs > 0
? Math.max(proxyTimeoutMs, DEFAULT_API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS)
: DEFAULT_API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS;
const serverKeepAliveTimeoutMs = readTimeoutMs(
env,
"API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS",
DEFAULT_API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS,
{
allowZero: true,
logger,
}
);
const serverHeadersTimeoutMs = readTimeoutMs(
env,
"API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS",
DEFAULT_API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS,
{
allowZero: true,
logger,
}
);
return {
proxyTimeoutMs,
serverRequestTimeoutMs: readTimeoutMs(
env,
"API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS",
sharedRequestTimeoutMs
? Math.max(sharedRequestTimeoutMs, derivedRequestTimeoutMs)
: derivedRequestTimeoutMs,
{
allowZero: true,
logger,
}
),
serverHeadersTimeoutMs:
serverHeadersTimeoutMs > 0 && serverKeepAliveTimeoutMs > 0
? Math.max(serverHeadersTimeoutMs, serverKeepAliveTimeoutMs + 1_000)
: serverHeadersTimeoutMs,
serverKeepAliveTimeoutMs,
serverSocketTimeoutMs: readTimeoutMs(
env,
"API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS",
DEFAULT_API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS,
{
allowZero: true,
logger,
}
),
};
}

View File

@@ -0,0 +1,80 @@
import test from "node:test";
import assert from "node:assert/strict";
const runtimeTimeouts = await import("../../src/shared/utils/runtimeTimeouts.ts");
test("upstream timeout config derives hidden fetch timeouts from FETCH_TIMEOUT_MS", () => {
const config = runtimeTimeouts.getUpstreamTimeoutConfig({
FETCH_TIMEOUT_MS: "600000",
STREAM_IDLE_TIMEOUT_MS: "600000",
});
assert.deepEqual(config, {
fetchTimeoutMs: 600000,
streamIdleTimeoutMs: 600000,
fetchHeadersTimeoutMs: 600000,
fetchBodyTimeoutMs: 600000,
fetchConnectTimeoutMs: 30000,
fetchKeepAliveTimeoutMs: 4000,
});
});
test("REQUEST_TIMEOUT_MS becomes the common timeout baseline when specific overrides are unset", () => {
const upstreamConfig = runtimeTimeouts.getUpstreamTimeoutConfig({
REQUEST_TIMEOUT_MS: "600000",
});
const apiBridgeConfig = runtimeTimeouts.getApiBridgeTimeoutConfig({
REQUEST_TIMEOUT_MS: "600000",
});
assert.equal(upstreamConfig.fetchTimeoutMs, 600000);
assert.equal(upstreamConfig.streamIdleTimeoutMs, 600000);
assert.equal(upstreamConfig.fetchHeadersTimeoutMs, 600000);
assert.equal(upstreamConfig.fetchBodyTimeoutMs, 600000);
assert.equal(apiBridgeConfig.proxyTimeoutMs, 600000);
assert.equal(apiBridgeConfig.serverRequestTimeoutMs, 600000);
});
test("upstream timeout config honors explicit overrides and falls back on invalid values", () => {
const config = runtimeTimeouts.getUpstreamTimeoutConfig({
REQUEST_TIMEOUT_MS: "550000",
FETCH_TIMEOUT_MS: "600000",
STREAM_IDLE_TIMEOUT_MS: "600000",
FETCH_HEADERS_TIMEOUT_MS: "610000",
FETCH_BODY_TIMEOUT_MS: "0",
FETCH_CONNECT_TIMEOUT_MS: "45000",
FETCH_KEEPALIVE_TIMEOUT_MS: "-1",
});
assert.equal(config.fetchHeadersTimeoutMs, 610000);
assert.equal(config.fetchBodyTimeoutMs, 0);
assert.equal(config.fetchConnectTimeoutMs, 45000);
assert.equal(config.fetchKeepAliveTimeoutMs, 4000);
});
test("TLS client timeout defaults to FETCH_TIMEOUT_MS and can be overridden", () => {
const defaultConfig = runtimeTimeouts.getTlsClientTimeoutConfig({
FETCH_TIMEOUT_MS: "600000",
});
const overriddenConfig = runtimeTimeouts.getTlsClientTimeoutConfig({
FETCH_TIMEOUT_MS: "600000",
TLS_CLIENT_TIMEOUT_MS: "720000",
});
assert.equal(defaultConfig.timeoutMs, 600000);
assert.equal(overriddenConfig.timeoutMs, 720000);
});
test("API bridge timeouts align request timeout with long proxy timeout by default", () => {
const config = runtimeTimeouts.getApiBridgeTimeoutConfig({
API_BRIDGE_PROXY_TIMEOUT_MS: "600000",
});
assert.deepEqual(config, {
proxyTimeoutMs: 600000,
serverRequestTimeoutMs: 600000,
serverHeadersTimeoutMs: 60000,
serverKeepAliveTimeoutMs: 5000,
serverSocketTimeoutMs: 0,
});
});