From 249a4917439558534d60489a0fadbb7cce8e6731 Mon Sep 17 00:00:00 2001 From: yyh Date: Mon, 5 Jan 2026 14:10:05 +0800 Subject: [PATCH] fix(nodejs-client): fix timeout handling in retry loop Fix critical bug in retry loop timeout control: - Move AbortController creation inside while loop to ensure each retry uses a fresh controller - Previous implementation caused retries to use an already-aborted controller, making retries fail immediately - Add eslint-disable comments to explain necessary type assertions - Improve code comments explaining DOM ReadableStream type conversion This fix ensures the retry mechanism works correctly with independent timeout control for each attempt. --- sdks/nodejs-client/src/http/client.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sdks/nodejs-client/src/http/client.ts b/sdks/nodejs-client/src/http/client.ts index fdfe9ecc09..c682ad4807 100644 --- a/sdks/nodejs-client/src/http/client.ts +++ b/sdks/nodejs-client/src/http/client.ts @@ -329,14 +329,15 @@ export class HttpClient { } } - const abortController = new AbortController(); - const timeoutId = setTimeout(() => abortController.abort(), timeout * 1000); - let attempt = 0; // `attempt` is a zero-based retry counter // Total attempts = 1 (initial) + maxRetries // e.g., maxRetries=3 means: attempt 0 (initial), then retries at 1, 2, 3 while (true) { + // Create a new AbortController for each attempt to handle timeouts properly + const abortController = new AbortController(); + const timeoutId = setTimeout(() => abortController.abort(), timeout * 1000); + try { const response = await fetch(url, { method, @@ -373,6 +374,9 @@ export class HttpClient { // For Node.js, we need to convert web streams to Node.js streams if (response.body) { const { Readable } = await import("node:stream"); + // Type assertion needed: DOM ReadableStream vs Node.js stream types are incompatible + // but Readable.fromWeb handles the conversion correctly at runtime + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument responseData = Readable.fromWeb(response.body as any); } else { throw new Error("Response body is null");