From 01ee312de68eae40f4c36a535f8694822540bae6 Mon Sep 17 00:00:00 2001 From: liuhao1024 Date: Sun, 5 Jul 2026 18:41:57 +0800 Subject: [PATCH] fix(telegram): forward keepalive limits into fallback transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- plugins/platforms/telegram/adapter.py | 23 ++++++++++++++----- tests/gateway/test_telegram_network.py | 31 ++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/plugins/platforms/telegram/adapter.py b/plugins/platforms/telegram/adapter.py index 5fc0dcbae1d..b23bdcf8d33 100644 --- a/plugins/platforms/telegram/adapter.py +++ b/plugins/platforms/telegram/adapter.py @@ -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) diff --git a/tests/gateway/test_telegram_network.py b/tests/gateway/test_telegram_network.py index 57950d0fb61..cede492fe5b 100644 --- a/tests/gateway/test_telegram_network.py +++ b/tests/gateway/test_telegram_network.py @@ -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