fix(telegram): recover when a polling-conflict retry fails - #27099
Closed
randiri100 wants to merge 1 commit into
Closed
fix(telegram): recover when a polling-conflict retry fails#27099randiri100 wants to merge 1 commit into
randiri100 wants to merge 1 commit into
Conversation
When a 409 "terminated by other getUpdates request" conflict triggers a retry and that retry's start_polling() itself fails, the conflict handler only logged the failure and returned, on the assumption that a "next conflict" callback would drive another retry attempt. But once start_polling() fails the long-poll is dead, so no error callback will ever fire again. There is no "next conflict" — the bot stays wedged with polling stopped until the gateway is manually restarted. Outbound sends keep working, which masks the failure. This is the same dead-end the network-error handler already guards against by self-scheduling its next retry. Apply the same pattern to the conflict handler: when a retry's start_polling() fails, self-schedule recovery — route transient network failures into the network reconnect ladder (which can escalate to a retryable-fatal gateway restart) and re-enter the conflict ladder otherwise. Add a regression test covering a conflict retry that fails with a network error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
Collaborator
Closed
3 tasks
Contributor
|
Closing in favor of #25630 (broader scope on the same bug — #23783 / silent-limbo after failed polling-conflict retry). Both PRs apply the same insight: Thanks for the parallel work. |
This was referenced Aug 3, 2026
Closed
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.
Problem
When Telegram returns a 409
Conflict: terminated by other getUpdates request,_handle_polling_conflictstops the updater, waits, and retriesstart_polling(). If that retry itself fails (e.g. aTimedOut/NetworkErrorbecause the host's connectivity is also flaky at that moment), theexceptblock only logs the failure andreturns — relying on a comment that says "wait for the next conflict to trigger another retry attempt".But once
start_polling()fails, the long-poll is dead and no error callback can ever fire again. There is no "next conflict". The bot is left permanently wedged with polling stopped, until the gateway process is manually restarted. Outbound sends keep working, which masks the failure — cron-driven messages still go out while the bot silently stops receiving anything.Observed in production: a 409 conflict at the same time as a brief network blip → one retry →
start_polling()raisedTimedOut→ handler returned → ~2h of dropped inbound messages until a manual restart.Fix
The network-error handler (
_handle_polling_network_error) already guards against this exact dead-end: when its retry'sstart_polling()fails, it self-schedules the next attempt instead of relying on a callback that can't fire.This applies the same pattern to the conflict handler. When a conflict retry's
start_polling()fails:_handle_polling_network_error(exponential-backoff ladder, which can escalate to a retryable-fatal gateway restart);Either way the recovery is self-scheduled as a background task, so the poller is never left wedged with nothing to wake it.
Test
Adds
test_conflict_retry_network_failure_schedules_recoverytotests/gateway/test_telegram_conflict.py, asserting a conflict retry that fails with a network error routes into the network reconnect ladder. Full suite (test_telegram_conflict.py+test_telegram_network_reconnect.py) passes — 22 tests.🤖 Generated with Claude Code