Skip to content

Honor server Keep-Alive timeout hints in the HTTP/1 connection pool - #1358

Open
quinnj wants to merge 1 commit into
masterfrom
claude/keepalive-timeout
Open

Honor server Keep-Alive timeout hints in the HTTP/1 connection pool#1358
quinnj wants to merge 1 commit into
masterfrom
claude/keepalive-timeout

Conversation

@quinnj

@quinnj quinnj commented Sep 10, 2026

Copy link
Copy Markdown
Member

Fixes #1155.

Problem

Servers such as Apache, nginx and HAProxy advertise their idle keep-alive window on responses as Keep-Alive: timeout=<seconds> (Apache's default is 5 seconds). The HTTP/1 pool only knew its own idle_timeout_ns (default 90 seconds), so a pooled connection could be handed out again well after the server had already closed it at its own deadline. An idempotent request then burned a retry (_retryable_reused_conn_error), and a non-idempotent one failed outright.

Change

  • Conn gains a keepalive_timeout_ns field. After a reusable response is read, _note_keepalive_hint! parses the response's Keep-Alive header and records the advertised window less a one-second safety margin. The margin exists because the server's clock starts when it finishes sending the response, before the client has finished reading it (this mirrors Node's undici keepAliveTimeoutThreshold).
  • _evict_expired_idle_locked! now expires an idle connection when it exceeds either the pool's idle_timeout_ns or the connection's own server-advertised bound, whichever is tighter.
  • A hint with no headroom (timeout=1 or timeout=0) marks the connection non-reusable, so the pool never keeps a connection the server is about to drop.
  • Parsing is tolerant of parameter order, whitespace, case (Timeout = 3), quoted values, and multiple header lines. Malformed or signed values are ignored (treated as no hint). Absurd values saturate instead of overflowing.
  • max=<n> is intentionally ignored: a server that exhausts it answers with Connection: close, which the pool already honors.
  • Transport docstring and CHANGELOG updated.

Tests

Added to test/http_client_transport_tests.jl:

  • Keep-Alive timeout hint parsing (#1155): 17 parser cases.
  • HTTP client transport evicts an idle conn past its server keep-alive window (#1155): pool idle timeout disabled, only the per-connection bound evicts the stale peer and the fresh one is reused.
  • HTTP client transport honors the server Keep-Alive timeout hint end to end (#1155): raw TCP server replies with timeout=5, max=100 (one connection serves both requests, pooled bound is 4s), max=100 (reused, no bound), and timeout=1 (not pooled, second request dials a new connection).

Locally test/http_client_transport_tests.jl passes in full (36 testsets, 0 failures) on Julia 1.12.6 with 4 threads.

🤖 Generated with Claude Code

Servers such as Apache, nginx and HAProxy advertise their idle keep-alive
window on responses as `Keep-Alive: timeout=<seconds>`. The pool only
knew its own `idle_timeout_ns` (default 90s), so a connection could be
handed out again after the server had already closed it at its own
(often 5s) deadline. Idempotent requests then burned a retry and
everything else failed outright.

Each `Conn` now records the advertised window (less a one-second safety
margin, since the server's clock starts before the client finishes
reading the response) and `_evict_expired_idle_locked!` applies it
alongside `idle_timeout_ns`, whichever is tighter. A hint that leaves no
headroom marks the connection non-reusable. `max=<n>` is ignored: a
server that exhausts it answers with `Connection: close`, which is
already honored.

Fixes #1155

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.45%. Comparing base (d6f049a) to head (c8f91d0).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1358      +/-   ##
==========================================
+ Coverage   89.42%   89.45%   +0.03%     
==========================================
  Files          31       31              
  Lines       12594    12627      +33     
==========================================
+ Hits        11262    11296      +34     
+ Misses       1332     1331       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

HTTP Keep-Alive header should be respected with connection pooling

1 participant