perf: size default ingest transport to worker count#17
Merged
Conversation
The httpClient fallback used http.DefaultClient, whose transport caps MaxIdleConnsPerHost at 2. Raising SetConcurrent past 2 then closed every connection beyond the first two, forcing a fresh TCP/TLS handshake on each flush and defeating the point of more workers. Replace the fallback with a lazily-built, cached client that clones http.DefaultTransport and sizes MaxIdleConnsPerHost (and MaxIdleConns when needed) to getConcurrent(), so each worker keeps its connection hot for reuse. The client is built once behind a sync.Once and shared across workers; a user-supplied client still passes through untouched. No client-level timeout is set, preserving the existing per-request context deadline. Co-Authored-By: Claude Opus 4.7 (1M context) <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.
Summary
The
httpClient()fallback usedhttp.DefaultClient, whose transport capsMaxIdleConnsPerHostat 2. Each ingest worker's flush is a synchronous blocking POST, so effective throughput scales withSetConcurrent— but raising it past 2 closed every connection beyond the first two, forcing a fresh TCP (and TLS) handshake on each flush and defeating the point of more workers.This replaces the bare fallback with a lazily-built, cached client whose transport is sized to the worker count:
http.DefaultTransport(preserves the dial/TLS/HTTP2 defaults).MaxIdleConnsPerHost = getConcurrent()so each worker keeps its connection hot for reuse.MaxIdleConnsonly when it's below the worker count (default 100 otherwise untouched).sync.Onceand shared across workers.Timeout— the existing per-request context deadline fromgetIngestTimeout()still bounds each flush, so behavior is unchanged.A user-supplied client via
SetHTTPClientstill passes through verbatim.Notes
httpClient()call, which in the ingest path is always aftersetup(), so the worker count is locked in. The only mismatch window is the unusualSearch→SetConcurrent→Ingestordering, matching the existing assumption that setters run before use.MaxConnsPerHostis left unlimited: each worker issues at most one in-flight request, so total connections are already bounded by the worker count without risking a worker blocking on the pool.Test plan
client_internal_test.go): default transport sized toconcurrent, default client cached across calls, user client passthrough.go vet ./...cleango test ./...passgo test -race ./...pass🤖 Generated with Claude Code