Skip to content

fix: enable TCP keepalive on default httpx transports to prevent NAT idle-timeout drops (#3269)#3503

Open
zaid646 wants to merge 4 commits into
openai:mainfrom
zaid646:fix/tcp-keepalive
Open

fix: enable TCP keepalive on default httpx transports to prevent NAT idle-timeout drops (#3269)#3503
zaid646 wants to merge 4 commits into
openai:mainfrom
zaid646:fix/tcp-keepalive

Conversation

@zaid646

@zaid646 zaid646 commented Jul 14, 2026

Copy link
Copy Markdown

Fixes #3269

Non-streaming API calls hang indefinitely behind NAT gateways because the default httpx transport has no TCP keepalive. Server-side generation routinely takes 300-700s, exceeding NAT idle timeouts (~120-350s).

Changes:

  • Adds _build_keepalive_socket_options() with SO_KEEPALIVE, TCP_KEEPIDLE=60s (Linux) / TCP_KEEPALIVE=60s (macOS), TCP_KEEPINTVL=60s, TCP_KEEPCNT=5
  • Runtime detection via inspect.signature - no dependency bump (httpx>=0.23.0 preserved)
  • _TRANSPORT_PASSTHROUGH_KEYS forwards verify/cert/trust_env/http1/http2/limits to the transport
  • kwargs.setdefault + if transport not in kwargs ensures custom transports are never overridden
  • Tests for sync + async keepalive and custom client preservation

…idle-timeout drops (openai#3269)

Non-streaming API calls (completions.create, Responses API with
medium/high reasoning) hang indefinitely behind NAT gateways because
the default httpx transport has no TCP keepalive. Server-side
generation routinely takes 300-700s, exceeding NAT idle timeouts
(~120-350s), and the dead connection is never detected.

This adds SO_KEEPALIVE with TCP_KEEPIDLE=60s, TCP_KEEPINTVL=60s,
and TCP_KEEPCNT=5 on both _DefaultHttpxClient and
_DefaultAsyncHttpxClient, using runtime detection of the
socket_options parameter (httpx>=0.25.0) to avoid bumping the
dependency floor. Custom transports supplied via http_client=
are never overridden.
@zaid646 zaid646 requested a review from a team as a code owner July 14, 2026 12:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44c7df4cfc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/openai/_base_client.py Outdated
Comment on lines +872 to +873
if "transport" not in kwargs:
kwargs["transport"] = _build_keepalive_transport(httpx.HTTPTransport, kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve environment proxy discovery

For users relying on HTTP_PROXY/HTTPS_PROXY with the default trust_env=True, this unconditional injected transport prevents httpx from loading environment proxy mounts because httpx only enables env proxy discovery when transport is None. As a result DefaultHttpxClient()/OpenAI() bypasses required corporate proxies or fails to connect, and the existing test_proxy_environment_variables expectation that _mounts contains the env proxy will no longer hold; the async default transport path has the same issue.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicitly passing a transport to httpx bypasses env proxy detection
(HTTP_PROXY/HTTPS_PROXY/ALL_PROXY). This adds a proxy-var gate that
skips keepalive transport injection when proxy env vars are detected
and trust_env hasn't been explicitly disabled.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ad65fe086

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tests/test_client.py Outdated
)

def test_default_transport_has_tcp_keepalive(self) -> None:
client = OpenAI(base_url=base_url, api_key=api_key)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ensure keepalive tests clear proxy env

This test depends on the runner having no HTTP_PROXY/HTTPS_PROXY/ALL_PROXY variables. In an environment where any of those are already set, _should_inject_keepalive_transport() deliberately skips injecting the transport, so socket_options will not include SO_KEEPALIVE and the assertion below fails; the async copy has the same issue. Clear the proxy env vars in these keepalive-positive tests or instantiate with trust_env=False.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d219cc78fa

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

httpx.HTTPTransport.__init__
).parameters

_TRANSPORT_PASSTHROUGH_KEYS = ("verify", "cert", "trust_env", "http1", "http2", "limits")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply keepalive to explicit proxy transports

When callers use the documented DefaultHttpxClient(proxy=...) path, _should_inject_keepalive_transport still adds a direct transport, but proxy is not forwarded here and remains in kwargs; httpx routes those requests through a separate proxy transport that it builds from the proxy kwarg, so the injected transport with socket_options is bypassed and proxied calls still have no TCP keepalive. This leaves the idle-timeout hang unfixed for explicit proxy users; construct the proxy transport with the same socket options or handle the proxy kwarg consistently.

Useful? React with 👍 / 👎.

@zaid646

zaid646 commented Jul 14, 2026

Copy link
Copy Markdown
Author

@codex review

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.

[Bug] Non-streaming calls silently hang forever behind NAT — default httpx transport has no TCP keepalive

1 participant