fix(telegram): fall back to reachable IP when proxy can't reach primary anycast IP - #59090
fix(telegram): fall back to reachable IP when proxy can't reach primary anycast IP#59090Djaler wants to merge 1 commit into
Conversation
The fallback-IP transport and TELEGRAM_PROXY were mutually exclusive: the adapter only engaged TelegramFallbackTransport when no proxy was set, and _is_retryable_connect_error() excluded httpx.ProxyError (which is not a subclass of httpx.ConnectError). When TELEGRAM_PROXY points at a proxy whose upstream egress can only reach a subset of the api.telegram.org anycast block (e.g. a DPI-bypass router), the primary DNS path resolves to an IP the proxy cannot reach and raises ProxyError 'Host unreachable'. Because that error was non-retryable and the fallback branch was skipped whenever a proxy was configured, the whole request failed instead of falling through to a reachable fallback IP. Fixes: - Treat httpx.ProxyError as retryable so the transport falls through to the configured/discovered fallback IPs. - Engage TelegramFallbackTransport whenever fallback IPs are present (it threads TELEGRAM_PROXY through internally), so proxy + pinned-IP work together. Log line distinguishes the proxied path. Verified against tests/gateway/test_telegram_network*.py and related Telegram suites (104 passed).
Related: #58790 (parent CLOSE_WAIT fd-leak issue, now closed) and its fixes #58804/#58803 (keepalive limits in the fallback transport), and #47172 (open — proxy-exhaustion diagnostic hint). This PR fixes a different mechanism in the same |
|
Thanks for isolating this to the existing Telegram fallback transport. The premise is present on current main: Problems
Suggested changes
This is an automated hermes-sweeper review. |
Summary
TELEGRAM_PROXYand the fallback-IP transport were mutually exclusive, so a proxy whose upstream egress can only reach part of theapi.telegram.organycast block (e.g. a DPI-bypass router) could not connect at all — even when a reachable Telegram IP existed.Two root causes:
_is_retryable_connect_error()excludedhttpx.ProxyError.httpx.ProxyErroris not a subclass ofhttpx.ConnectError, so when the primary DNS path resolved to an IP the proxy couldn't reach, the resultingProxyError: Host unreachablewas treated as fatal and the transport never fell through to the fallback IPs.The adapter engaged
TelegramFallbackTransportonly when no proxy was set (if fallback_ips and not proxy_url). With a proxy configured, plain httpx DNS picked an unreachable IP and there was no IP-pinning fallback.Fix
httpx.ProxyErroras retryable so the transport falls through to the configured/discovered fallback IPs.TelegramFallbackTransportwhenever fallback IPs are present (it already threadsTELEGRAM_PROXYthrough internally), so proxy + pinned IPs work together. The log line now distinguishes the proxied path.Net diff:
+35 / -7across two files, no behavior change for the default (no-proxy, no-fallback) path.Repro
With
TELEGRAM_PROXY=socks5://<proxy>where the proxy's egress reaches only a subset of Telegram's anycast IPs, the gateway logged repeatedProxy Server could not connect: Host unreachable.and never connected. After this change it falls through to the reachable IP and polling succeeds.Test Plan
Ran the relevant Telegram suites locally — 104 passed:
tests/gateway/test_telegram_network.pytests/gateway/test_telegram_network_reconnect.pytests/gateway/test_telegram_send_path_health.pytests/gateway/test_telegram_conflict.pytests/gateway/test_telegram_init_deadline.pytests/gateway/test_telegram_closewait_limits_31599.pytests/gateway/test_telegram_send_draft_format.pyNo new env vars, no config surface, no core-tool changes — a self-contained bug fix in the Telegram adapter's connection path.