wiwiway / src /shared /utils /runtimeTimeouts.ts
Claude Code
Sync gateway codebase without binaries
116b4cb
Raw
History Blame Contribute Delete
5.56 kB
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,
}
),
};
}