From 575111d32f197c37b833effe17b2de0778c1c509 Mon Sep 17 00:00:00 2001 From: Yanhu007 Date: Sun, 12 Apr 2026 00:15:30 +0000 Subject: [PATCH] fix: remove abort listener on successful fetch to prevent Deno hang When fetchWithTimeout receives an external signal, it adds an abort event listener to forward cancellation to its internal controller. On successful completion, the listener was not removed. On Deno, AbortSignal.timeout() refs its underlying timer when listeners are attached. The orphaned listener kept the timer alive for the full timeout duration, preventing clean process exit. Add signal.removeEventListener in the finally block. Fixes #1811 --- src/client.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/client.ts b/src/client.ts index f55a6b986..06a9b81fe 100644 --- a/src/client.ts +++ b/src/client.ts @@ -892,6 +892,11 @@ export class OpenAI { return await this.fetch.call(undefined, url, fetchOptions); } finally { clearTimeout(timeout); + // Remove the forwarding listener so the caller's signal (and any + // underlying timer, e.g. AbortSignal.timeout()) can be GC'd + // immediately. Without this, Deno keeps the timer ref'd for the + // full timeout duration, preventing clean process exit. See #1811. + if (signal) signal.removeEventListener('abort', abort); } }