Skip to content

SMOODEV-2513: add bounded connect timeout to .NET SmooAI.Fetch#91

Open
brentrager wants to merge 1 commit into
mainfrom
SMOODEV-2513-connect-timeout-dotnet
Open

SMOODEV-2513: add bounded connect timeout to .NET SmooAI.Fetch#91
brentrager wants to merge 1 commit into
mainfrom
SMOODEV-2513-connect-timeout-dotnet

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

Parity with Rust PR #88 (SMOODEV-2498). api-prime's ~16s API stalls (SMOODEV-2481) traced to fresh SYNs black-holing to dead pod IPs still lingering in a ClusterIP's iptables during an endpoint-removal race. With no connect timeout, the client waits the full whole-request timeout before the existing retry can land on a live pod.

Fix

Add a bounded connect timeout so a black-holed connect fails in ~the configured window and the existing retry lands on a live endpoint, while slow-but-alive handlers (governed by the whole-request timeout) are untouched.

  • SmooFetchBuilder.WithConnectTimeout(TimeSpan) — mirrors WithTimeout.
  • SmooFetchOptions.ConnectTimeout: TimeSpan?default null, so existing consumers are behaviorally unchanged.
  • Self-managed Create(...) path now builds a SocketsHttpHandler and sets handler.ConnectTimeout only when the option is set (unset → handler default = Infinite, byte-identical to before).

IHttpClientFactory caveat

ConnectTimeout is only applied on the SDK-owned handler (Create). For RequireHttpClientFactory / DI-managed clients the factory owns the handler, so the connect timeout must be configured at registration, e.g. .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler { ConnectTimeout = ... }). Documented inline in CreateFromFactory.

Test

ConnectTimeoutTests.cs: a connect to a non-routable black-hole IP (10.255.255.1:80) with a 500ms ConnectTimeout and a 5s whole-request timeout throws in ~0.5s (asserted < 3s) instead of hanging to the whole timeout. Full suite green (dotnet test: 32 passed), dotnet format --verify-no-changes clean.

🤖 Generated with Claude Code

…y with #88)

Mirror the Rust connect-timeout port. api-prime stalls (SMOODEV-2481) trace
to fresh SYNs black-holing to dead pod IPs still in a ClusterIP's iptables;
without a connect timeout the client waits the whole-request timeout before a
retry can land on a live endpoint.

- SmooFetchOptions.ConnectTimeout (TimeSpan?), default null -> unchanged.
- SmooFetchBuilder.WithConnectTimeout, mirrors WithTimeout.
- Self-managed client uses SocketsHttpHandler; sets ConnectTimeout only when set.
- IHttpClientFactory-managed clients: caveat documented (factory owns handler).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 21d3543

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant