Files
7ef82473d9 fix(workers): fix headers timeout for AI interference jobs. (#2888)
* Fix headers timeout for AI interference jobs.

* Take greptile feedback into account

* Fix  OpenAI timeouts and node 24 incompatibility.

Use undici's own fetch together with its Agent/ProxyAgent so that both
always come from the same undici copy. Passing an npm undici Agent as
the dispatcher of the runtime's built-in fetch fails immediately on
Node >= 24, which bundles a different undici major (undici 7).

The OpenAI client now sets headersTimeout/bodyTimeout from
OPENAI_TIMEOUT_SEC via the Agent dispatcher, so slow OpenAI-compatible
servers are no longer cut off by undici's default 5 minute header
timeout. Log fetch failures with their underlying cause for easier
debugging.

* refactor: simplify inference fetch timeout handling

Replace the manual header/body timers, signal merging and dynamic undici
import with a single helper that pairs undici's fetch with an Agent (or
ProxyAgent) whose headersTimeout/bodyTimeout match the configured timeout.
Overall deadlines are already enforced by the inference job timeout and
the OpenAI SDK's own timeout.

* Reuse undici dispatchers across inference client builds

---------

Co-authored-by: Mohamed Bassem <me@mbassem.com>
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
2026-10-04 20:59:55 +01:00

36 lines
1.4 KiB
TypeScript

import { Agent, Dispatcher, ProxyAgent, fetch as undiciFetch } from "undici";
// Dispatchers are reused across calls so that clients built per job (e.g. the
// inference, embeddings and asset-preprocessing workers) share a connection
// pool instead of opening fresh sockets each time.
const dispatchers = new Map<string, Dispatcher>();
function getDispatcher(timeoutMs: number, proxyUrl?: string): Dispatcher {
const key = `${proxyUrl ?? ""}:${timeoutMs}`;
let dispatcher = dispatchers.get(key);
if (!dispatcher) {
const opts = { headersTimeout: timeoutMs, bodyTimeout: timeoutMs };
dispatcher = proxyUrl
? new ProxyAgent({ uri: proxyUrl, ...opts })
: new Agent(opts);
dispatchers.set(key, dispatcher);
}
return dispatcher;
}
// Creates a fetch whose undici headers/body timeouts match the given timeout.
// Without this, undici's defaults (5 mins) cut off slow inference requests
// regardless of the configured timeout. We use undici's own fetch alongside
// its Agent so that the fetch and the dispatcher come from the same undici copy.
export function createCustomFetch(
timeoutMs: number,
proxyUrl?: string,
): typeof fetch {
const dispatcher = getDispatcher(timeoutMs, proxyUrl);
return ((input: RequestInfo | URL, init?: RequestInit) =>
undiciFetch(
input as Parameters<typeof undiciFetch>[0],
{ ...init, dispatcher } as Parameters<typeof undiciFetch>[1],
)) as unknown as typeof fetch;
}