Fix synthesis fetch failures from Node's default 5-minute HTTP timeout
Nothing published for hours, every cluster failing with "fetch failed". Ollama's own log showed the real story: requests being cancelled at exactly 5m0s with a 500, not a model or server error. Node's global fetch (undici) defaults to a 5-minute headers/body timeout, and CPU-only prompt processing on the reference hardware (i5-6600K, no GPU, ~17 tok/s) legitimately takes longer than that once prompts carry full article bodies instead of short blurbs (the previous fix in this same line of work) — every generate() call past a few thousand tokens got killed client-side before Ollama could finish. OllamaProvider.generate() now passes a dedicated undici Agent with headersTimeout/bodyTimeout disabled as the fetch dispatcher, so the request runs as long as it actually needs to. Verified the failure mode and the fix directly: a short-timeout dispatcher against a deliberately slow server reproduces the exact same "fetch failed" / UND_ERR_HEADERS_TIMEOUT error seen in production, and a zero-timeout dispatcher completes the same slow request without issue. undici was already a transitive dependency (via jsdom); added directly since ollama-provider.ts now imports from it.
This commit is contained in:
Generated
+2
-1
@@ -15,7 +15,8 @@
|
|||||||
"fastify": "^5.10.0",
|
"fastify": "^5.10.0",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^29.1.1",
|
||||||
"rss-parser": "^3.13.0",
|
"rss-parser": "^3.13.0",
|
||||||
"telegram": "^2.26.22"
|
"telegram": "^2.26.22",
|
||||||
|
"undici": "^7.28.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jsdom": "^28.0.3",
|
"@types/jsdom": "^28.0.3",
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
"fastify": "^5.10.0",
|
"fastify": "^5.10.0",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^29.1.1",
|
||||||
"rss-parser": "^3.13.0",
|
"rss-parser": "^3.13.0",
|
||||||
"telegram": "^2.26.22"
|
"telegram": "^2.26.22",
|
||||||
|
"undici": "^7.28.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jsdom": "^28.0.3",
|
"@types/jsdom": "^28.0.3",
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
|
import { Agent } from 'undici';
|
||||||
import type { InferenceProvider } from './provider.js';
|
import type { InferenceProvider } from './provider.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node's global fetch (undici) defaults to a 5-minute headers/body timeout — fine for
|
||||||
|
* ordinary HTTP calls, but a real problem for /api/generate on CPU-only inference: a
|
||||||
|
* near-full context window can legitimately take longer than that just for prompt
|
||||||
|
* processing on the reference hardware (i5-6600K, no GPU, ~17 tokens/sec). Once
|
||||||
|
* synthesis prompts started carrying full article bodies instead of short blurbs, every
|
||||||
|
* generate() call past a few thousand tokens got killed at exactly 5m0s — visible in
|
||||||
|
* Ollama's own log as the request being cancelled, not a genuine model/server error —
|
||||||
|
* so no cluster could ever finish synthesizing. No timeout at all here; Ollama's own
|
||||||
|
* process is the natural backstop, not a clock tuned for hardware this doesn't run on.
|
||||||
|
*/
|
||||||
|
const noTimeoutDispatcher = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default context window / max-generation length requested from Ollama when a caller
|
* Default context window / max-generation length requested from Ollama when a caller
|
||||||
* doesn't specify its own. Ollama otherwise falls back to whatever the model's
|
* doesn't specify its own. Ollama otherwise falls back to whatever the model's
|
||||||
@@ -51,8 +65,11 @@ export class OllamaProvider implements InferenceProvider {
|
|||||||
num_ctx: opts.numCtx ?? DEFAULT_NUM_CTX,
|
num_ctx: opts.numCtx ?? DEFAULT_NUM_CTX,
|
||||||
num_predict: opts.numPredict ?? DEFAULT_NUM_PREDICT
|
num_predict: opts.numPredict ?? DEFAULT_NUM_PREDICT
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
});
|
// Not in the ambient RequestInit type this project resolves to, but Node's global
|
||||||
|
// fetch (built on undici) honors it at runtime — see noTimeoutDispatcher above.
|
||||||
|
dispatcher: noTimeoutDispatcher
|
||||||
|
} as RequestInit);
|
||||||
if (!res.ok) throw new Error(`Ollama generate failed: ${res.status} ${await res.text()}`);
|
if (!res.ok) throw new Error(`Ollama generate failed: ${res.status} ${await res.text()}`);
|
||||||
const data = (await res.json()) as { response: string };
|
const data = (await res.json()) as { response: string };
|
||||||
return data.response;
|
return data.response;
|
||||||
|
|||||||
Reference in New Issue
Block a user