Skip to content

perf: size default ingest transport to worker count#17

Merged
acoshift merged 1 commit into
mainfrom
perf/ingest-default-transport
May 25, 2026
Merged

perf: size default ingest transport to worker count#17
acoshift merged 1 commit into
mainfrom
perf/ingest-default-transport

Conversation

@acoshift
Copy link
Copy Markdown
Member

Summary

The httpClient() fallback used http.DefaultClient, whose transport caps MaxIdleConnsPerHost at 2. Each ingest worker's flush is a synchronous blocking POST, so effective throughput scales with SetConcurrent — 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:

  • Clones http.DefaultTransport (preserves the dial/TLS/HTTP2 defaults).
  • Sets MaxIdleConnsPerHost = getConcurrent() so each worker keeps its connection hot for reuse.
  • Bumps MaxIdleConns only when it's below the worker count (default 100 otherwise untouched).
  • Built once behind a sync.Once and shared across workers.
  • No client-level Timeout — the existing per-request context deadline from getIngestTimeout() still bounds each flush, so behavior is unchanged.

A user-supplied client via SetHTTPClient still passes through verbatim.

Notes

  • The pool is sized at the first httpClient() call, which in the ingest path is always after setup(), so the worker count is locked in. The only mismatch window is the unusual SearchSetConcurrentIngest ordering, matching the existing assumption that setters run before use.
  • MaxConnsPerHost is 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

  • New white-box tests (client_internal_test.go): default transport sized to concurrent, default client cached across calls, user client passthrough.
  • go vet ./... clean
  • go test ./... pass
  • go test -race ./... pass

🤖 Generated with Claude Code

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>
@acoshift acoshift merged commit cf28170 into main May 25, 2026
1 check passed
@acoshift acoshift deleted the perf/ingest-default-transport branch May 25, 2026 13:14
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