Skip to content

Add HTTP/2 PING keepalive to prevent idle connection timeouts#1081

Open
balaji-g wants to merge 1 commit intoencode:masterfrom
balaji-g:add-h2-ping-keepalive
Open

Add HTTP/2 PING keepalive to prevent idle connection timeouts#1081
balaji-g wants to merge 1 commit intoencode:masterfrom
balaji-g:add-h2-ping-keepalive

Conversation

@balaji-g
Copy link
Copy Markdown

@balaji-g balaji-g commented Apr 30, 2026

Summary

Many cloud load balancers and network proxies terminate idle TCP connections after a fixed timeout. HTTP/2 PING frames (RFC 9113 §6.7) are the standard mechanism to keep connections alive, but httpcore does not currently send them — meaning any HTTP/2 request that takes longer than the idle timeout will fail with a disconnect error.

This adds a background keepalive thread that sends periodic HTTP/2 PING frames on active connections. It can be enabled via:

  • Constructor parameter: h2_ping_interval on ConnectionPool / HTTPConnection / HTTP2Connection
  • Environment variable: HTTPCORE_H2_PING_INTERVAL (value in seconds)

The env var approach is particularly important because it allows users of higher-level clients (httpx, OpenAI Python SDK) to enable PING keepalive without any code changes.

Example

import httpcore

# Via constructor
pool = httpcore.ConnectionPool(http2=True, h2_ping_interval=60)

# Or via environment variable (no code changes needed)
# export HTTPCORE_H2_PING_INTERVAL=60
pool = httpcore.ConnectionPool(http2=True)

Design decisions

  • Daemon thread: The PING loop runs in a daemon thread using threading.Event.wait() for the interval, avoiding interference with the async event loop.
  • Thread safety: PING writes are protected by a dedicated threading.Lock to avoid races with the main h2 state machine.
  • Env var fallback: HTTPCORE_H2_PING_INTERVAL is read at connection init time. An explicit constructor value always takes precedence.
  • Graceful shutdown: The PING thread is stopped and joined on close() / aclose().

Related issue: #1080

Checklist

@balaji-g balaji-g force-pushed the add-h2-ping-keepalive branch 9 times, most recently from 43fa25f to da08e37 Compare May 1, 2026 00:12
Many cloud load balancers and proxies (e.g. AWS Global Accelerator)
terminate idle TCP connections after a fixed timeout (often 340s).
HTTP/2 PING frames (RFC 9113 §6.7) reset this idle timer, but
httpcore does not currently send them.

This adds a background thread that sends periodic HTTP/2 PING frames
on active connections, configurable via:

- `h2_ping_interval` parameter on ConnectionPool / HTTPConnection
- `HTTPCORE_H2_PING_INTERVAL` environment variable (seconds)

The env var allows enabling PING keepalive without any code changes,
which is critical for users of higher-level clients like httpx and
the OpenAI Python SDK that don't expose httpcore internals.

Closes encode#1080

Made-with: Cursor
@balaji-g balaji-g force-pushed the add-h2-ping-keepalive branch from da08e37 to 2b668b2 Compare May 1, 2026 00:25
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