fix: improve abort signal handling for fetch requests in mlx and llamacpp extensions (#7552)

This commit is contained in:
since-2017-hub
2026-02-26 20:36:01 -07:00
committed by GitHub
parent 735cd5b05e
commit fc2d0bcb30
2 changed files with 40 additions and 10 deletions

View File

@@ -1641,16 +1641,31 @@ export default class llamacpp_extension extends AIEngine {
body: string,
abortController?: AbortController
): AsyncIterable<chatCompletionChunk> {
// AbortSignal.any() is not available in all runtimes (e.g. WebKit/JavaScriptCore),
// so we manually combine the timeout and external abort signals.
const combinedController = new AbortController()
const timeoutId = setTimeout(
() => combinedController.abort(new Error('Request timed out')),
this.timeout * 1000
)
if (abortController?.signal) {
if (abortController.signal.aborted) {
combinedController.abort(abortController.signal.reason)
} else {
abortController.signal.addEventListener(
'abort',
() => combinedController.abort(abortController.signal.reason),
{ once: true }
)
}
}
const response = await fetch(url, {
method: 'POST',
headers,
body,
connectTimeout: Number(this.timeout) * 1000, // default 10 minutes
signal: AbortSignal.any([
AbortSignal.timeout(this.timeout * 1000),
abortController?.signal,
]),
})
signal: combinedController.signal,
}).finally(() => clearTimeout(timeoutId))
if (!response.ok) {
const errorData = await response.json().catch(() => null)
throw new Error(

View File

@@ -427,15 +427,30 @@ export default class mlx_extension extends AIEngine {
body: string,
abortController?: AbortController
): AsyncIterable<chatCompletionChunk> {
// AbortSignal.any() is not available in all runtimes (e.g. WebKit/JavaScriptCore),
// so we manually combine the timeout and external abort signals.
const combinedController = new AbortController()
const timeoutId = setTimeout(
() => combinedController.abort(new Error('Request timed out')),
this.timeout * 1000
)
if (abortController?.signal) {
if (abortController.signal.aborted) {
combinedController.abort(abortController.signal.reason)
} else {
abortController.signal.addEventListener(
'abort',
() => combinedController.abort(abortController.signal.reason),
{ once: true }
)
}
}
const response = await fetch(url, {
method: 'POST',
headers,
body,
signal: AbortSignal.any([
AbortSignal.timeout(this.timeout * 1000),
abortController?.signal,
]),
})
signal: combinedController.signal,
}).finally(() => clearTimeout(timeoutId))
if (!response.ok) {
const errorData = await response.json().catch(() => null)