[Repo Assist] fix: reuse SocketsHttpHandler to prevent SNAT port exhaustion#216
Draft
github-actions[bot] wants to merge 1 commit intomasterfrom
Draft
Conversation
…198) The default HttpClient factory created a fresh SocketsHttpHandler on every request, which discarded the TCP connection pool immediately. This caused SNAT port exhaustion on Azure and similar environments. Introduce a process-wide lazy-singleton SocketsHttpHandler for the common case (no proxy, no custom handler transformers, default cert strategy, default decompression). Each request still gets its own HttpClient wrapper (using HttpClient(handler, disposeHandler=false)) so per-request Timeout and httpClientTransformers continue to work correctly. The handler — and its connection pool — is never disposed, giving the same behaviour as a recommended DI-managed IHttpClientFactory. When any handler customisation is present the factory falls back to creating a fresh handler per request (existing behaviour), so there is no regression for users who already configure a custom factory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 This pull request was created by Repo Assist, an automated AI assistant.
Closes #198
Root cause
Defaults.defaultHttpClientFactorywas called once per request, creating a freshSocketsHttpHandlereach time.SocketsHttpHandlerholds the TCP connection pool, so discarding it after every request meant no connection reuse. On Azure (and any environment using SNAT), this exhausts outbound ports quickly.Fix
Introduce a process-wide lazy singleton
SocketsHttpHandlerfor the common (default) configuration. Each request still creates its ownHttpClientwrapper, but usesHttpClient(handler, disposeHandler=false)so the handler — and its connection pool — is never torn down.The shared handler is used only when:
certErrorStrategy = DefaulthttpClientHandlerTransformersare registereddefaultDecompressionMethodsmatches the built-in defaultIn all other cases the factory falls back to creating a fresh handler per request (existing behaviour), so users with custom configurations are unaffected.
Why this design?
Config.httpClientFactorysignature unchanged;httpClientTransformersand per-requestTimeoutstill work.PooledConnectionLifetime = 5 minalready ensures DNS changes are respected.Trade-offs
SocketsHttpHandler.Test Status
Build: ✅
dotnet build src/FsHttp/FsHttp.fsproj— succeeded, 0 warnings, 0 errors.Tests:⚠️ Infrastructure issue — the CI runner does not have .NET 6.0 installed (available: 8.0, 9.0, 10.0), so
dotnet testaborts before running any test. This is a pre-existing environment issue unrelated to this change. There is also a pre-existingNU1504duplicateFsUnitreference warning inTests.fsprojcaused by open Dependabot PRs (#204, #208).