fix(telegram): forward keepalive limits into fallback transport

httpx ignores the client-level `limits` kwarg when a custom `transport`
is supplied.  The #31599 keepalive fix injected limits via
`httpx_kwargs[limits]`, but the fallback-IP branch also passes a
custom `TelegramFallbackTransport` — so the limits were silently
discarded and the inner AsyncHTTPTransport instances ran with httpx
defaults (keepalive_expiry=5.0), leaking CLOSE_WAIT fds.

Pass the tuned limits directly into `TelegramFallbackTransport`
via `transport_kwargs` so its inner transports honour keepalive_expiry.
Only affects the fallback-IP branch; proxy and direct-DNS branches
continue to use `_with_limits()` as before.

Fixes #58790
This commit is contained in:
liuhao1024 2026-07-05 18:41:57 +08:00 committed by kshitij
parent 368e5f197e
commit 01ee312de6
2 changed files with 48 additions and 6 deletions

View file

@ -3054,17 +3054,28 @@ class TelegramAdapter(BasePlatformAdapter):
)
# Keep request/update pools separate to reduce contention during
# polling reconnect + bot API bootstrap/delete_webhook calls.
# httpx ignores the client-level `limits` kwarg when a custom
# `transport` is supplied (#58790). Pass the tuned limits
# directly into TelegramFallbackTransport so its inner
# AsyncHTTPTransport instances honour keepalive_expiry.
_transport_kwargs: dict = {}
if _pool_limits is not None:
_transport_kwargs["limits"] = _pool_limits
request = HTTPXRequest(
**request_kwargs,
httpx_kwargs=_with_limits(
{"transport": TelegramFallbackTransport(fallback_ips)}
),
httpx_kwargs={
"transport": TelegramFallbackTransport(
fallback_ips, **_transport_kwargs
)
},
)
get_updates_request = HTTPXRequest(
**request_kwargs,
httpx_kwargs=_with_limits(
{"transport": TelegramFallbackTransport(fallback_ips)}
),
httpx_kwargs={
"transport": TelegramFallbackTransport(
fallback_ips, **_transport_kwargs
)
},
)
elif proxy_url:
logger.info("[%s] Proxy detected; passing explicitly to HTTPXRequest: %s", self.name, proxy_url)

View file

@ -354,6 +354,37 @@ class TestFallbackTransportInit:
assert len(seen_kwargs) == 2
assert all("proxy" not in kwargs for kwargs in seen_kwargs)
def test_forwards_limits_to_inner_transports(self, monkeypatch):
"""Verify that caller-supplied limits reach the inner
AsyncHTTPTransport instances (#58790). httpx ignores the
client-level limits kwarg when a custom transport is
supplied, so the limits must be forwarded via transport_kwargs.
"""
seen_kwargs = []
def factory(**kwargs):
seen_kwargs.append(kwargs.copy())
return FakeTransport([], {})
for key in ("HTTPS_PROXY", "HTTP_PROXY", "ALL_PROXY", "https_proxy", "http_proxy", "all_proxy", "TELEGRAM_PROXY", "NO_PROXY", "no_proxy"):
monkeypatch.delenv(key, raising=False)
monkeypatch.setattr(tnet.httpx, "AsyncHTTPTransport", factory)
custom_limits = httpx.Limits(
max_connections=42,
max_keepalive_connections=10,
keepalive_expiry=30.0,
)
transport = tnet.TelegramFallbackTransport(
["149.154.167.220"], limits=custom_limits
)
# 1 primary + 1 fallback = 2 AsyncHTTPTransport instances
assert len(seen_kwargs) == 2
for kw in seen_kwargs:
assert "limits" in kw
assert kw["limits"] is custom_limits
class TestFallbackTransportClose:
@pytest.mark.asyncio