fix(gateway): drain stale httpx polling connections on Telegram reconnect#17015
Merged
Conversation
Collaborator
…nect Network errors through proxies (e.g. sing-box) can leave httpx connections in a half-closed state occupying pool slots. After enough reconnect cycles the 256-connection default fills up entirely, causing Pool timeout: All connections in the connection pool are occupied. Fix: cycle only the getUpdates request object (_request[0]) via shut-down + re-initialize before restarting polling. This drains stale connections without touching the general request (_request[1]) that concurrent send_message / edit_message calls rely on. The drain is applied to both _handle_polling_network_error and _handle_polling_conflict reconnect paths via a shared _drain_polling_connections() helper. Failures in the drain are swallowed so reconnect always proceeds. Based on #16466 by @Mirac1eSky.
2bf8240 to
8f0e2b8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Salvage of #16466 by @Mirac1eSky — drains stale httpx connections during Telegram polling reconnect to prevent pool exhaustion through proxy-related network errors.
What the original PR identified
When Telegram polling drops through a proxy (e.g. sing-box),
updater.stop()+start_polling()leaves the underlying httpx connections in a half-closed state. After enough cycles the default 256-connection pool fills up, causing:What changed from the original
The original PR called
bot.shutdown()+bot.initialize()which cycles both httpx connection pools:_request[0]— getUpdates (polling only)_request[1]— general (send_message, edit_message, etc.)This creates a race condition: any concurrent
send_message/edit_messagecall hitting_request[1]between shutdown and re-initialize getsRuntimeError("This HTTPXRequest is not initialized!"). Additionally,bot.initialize()callsget_me()(a network round-trip) which is likely to fail during network error recovery.Our fix targets only
_request[0](the polling request) viaHTTPXRequest.shutdown()+HTTPXRequest.initialize()directly. The general request is never touched, so concurrent message sends are safe. Noget_me()call is made.Additional improvements over original
bot.shutdown()— kills all connections_request[0]only — polling connections onlyget_me()during initialize (likely fails)_handle_polling_network_erroronly_handle_polling_network_errorAND_handle_polling_conflict_drain_polling_connections()helperexcept: pass_requesttuple structure, flags for PTB 23+ reviewTests
9 tests pass (4 existing + 5 new):
test_reconnect_drains_polling_request_only— verifies only_request[0]is cycled,_request[1]untouchedtest_reconnect_continues_if_drain_fails— both shutdown + initialize fail, reconnect still proceedstest_initialize_still_runs_when_shutdown_fails— shutdown raises but initialize is still called (separate try blocks)test_conflict_retry_also_drains_polling_connections— conflict path also drainstest_drain_helper_noop_without_app— graceful no-op when app is NoneE2E validated with realistic
MockHTTPXRequestobjects tracking shutdown/initialize state.Full gateway suite: 3844 passed, 61 skipped, 13 failed (all 13 failures pre-existing on main).
Files changed
gateway/platforms/telegram.py— new_drain_polling_connections()helper + calls in both reconnect paths (+40 lines)tests/gateway/test_telegram_network_reconnect.py— 5 new tests (+120 lines)scripts/release.py— add Mirac1eSky to AUTHOR_MAP (+1 line)