Skip to content

Commit 27d6133

Browse files
fix: resolve 30-second connection hang in v6.0.0+ (#408)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent cd290ff commit 27d6133

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"emoji-regex": "10.6.0",
4545
"form-data": "4.0.4",
4646
"ts-custom-error": "^3.2.0",
47+
"undici": "^7.16.0",
4748
"uuid": "11.1.0",
4849
"zod": "4.1.12"
4950
},

src/utils/fetch-with-retry.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Agent } from 'undici'
12
import type { HttpResponse, RetryConfig, CustomFetch, CustomFetchResponse } from '../types/http'
23
import { isNetworkError } from '../types/http'
34

@@ -14,6 +15,15 @@ const DEFAULT_RETRY_CONFIG: RetryConfig = {
1415
},
1516
}
1617

18+
/**
19+
* HTTP agent with keepAlive disabled to prevent hanging connections
20+
* This ensures the process exits immediately after requests complete
21+
*/
22+
const httpAgent = new Agent({
23+
keepAliveTimeout: 1, // Close connections after 1ms of idle time
24+
keepAliveMaxTimeout: 1, // Maximum time to keep connections alive
25+
})
26+
1727
/**
1828
* Converts Headers object to a plain object
1929
*/
@@ -113,6 +123,8 @@ export async function fetchWithRetry<T = unknown>(args: {
113123
const nativeResponse = await fetch(url, {
114124
...fetchOptions,
115125
signal: requestSignal,
126+
// @ts-expect-error - dispatcher is a valid option for Node.js fetch but not in the TS types
127+
dispatcher: httpAgent,
116128
})
117129
fetchResponse = convertResponseToCustomFetch(nativeResponse)
118130
}

0 commit comments

Comments
 (0)