From 9bcbdd6e9e81cac1496fef0117e3adae0a5d29dc Mon Sep 17 00:00:00 2001 From: kris <3207119952@qq.com> Date: Mon, 11 May 2026 21:49:10 +0800 Subject: [PATCH] fix(telegram): make polling conflict retryable with longer backoff When the gateway restarts, Telegram may take longer than 30s to release the old getUpdates session. Previously the adapter gave up permanently after 3x10s retries (retryable=False), leaving the platform dead until manual restart. Raise retries to 5x20s and mark the error retryable so the background reconnection loop keeps trying until the session expires. --- gateway/platforms/telegram.py | 6 +++--- tests/gateway/test_telegram_conflict.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gateway/platforms/telegram.py b/gateway/platforms/telegram.py index c1f312783a4d..215567c3aa5e 100644 --- a/gateway/platforms/telegram.py +++ b/gateway/platforms/telegram.py @@ -823,8 +823,8 @@ async def _handle_polling_conflict(self, error: Exception) -> None: # giving up, so the old session has time to expire. self._polling_conflict_count += 1 - MAX_CONFLICT_RETRIES = 3 - RETRY_DELAY = 10 # seconds + MAX_CONFLICT_RETRIES = 5 + RETRY_DELAY = 20 # seconds if self._polling_conflict_count <= MAX_CONFLICT_RETRIES: logger.warning( @@ -864,7 +864,7 @@ async def _handle_polling_conflict(self, error: Exception) -> None: % MAX_CONFLICT_RETRIES ) logger.error("[%s] %s Original error: %s", self.name, message, error) - self._set_fatal_error("telegram_polling_conflict", message, retryable=False) + self._set_fatal_error("telegram_polling_conflict", message, retryable=True) try: if self._app and self._app.updater: await self._app.updater.stop() diff --git a/tests/gateway/test_telegram_conflict.py b/tests/gateway/test_telegram_conflict.py index dcf31168848b..db132fe05a55 100644 --- a/tests/gateway/test_telegram_conflict.py +++ b/tests/gateway/test_telegram_conflict.py @@ -191,16 +191,16 @@ async def failing_start_polling(**kwargs): # Directly call _handle_polling_conflict to avoid event-loop scheduling # complexity. Each call simulates one 409 from Telegram. - for i in range(4): + for i in range(6): await adapter._handle_polling_conflict( conflict("Conflict: terminated by other getUpdates request") ) - # After 3 failed retries (count 1-3 each enter the retry branch but - # start_polling raises), the 4th conflict pushes count to 4 which - # exceeds MAX_CONFLICT_RETRIES (3), entering the fatal branch. + # After 5 failed retries (count 1-5 each enter the retry branch but + # start_polling raises), the 6th conflict pushes count to 6 which + # exceeds MAX_CONFLICT_RETRIES (5), entering the fatal branch. assert adapter.fatal_error_code == "telegram_polling_conflict", ( - f"Expected fatal after 4 conflicts, got code={adapter.fatal_error_code}, " + f"Expected fatal after 6 conflicts, got code={adapter.fatal_error_code}, " f"count={adapter._polling_conflict_count}" ) assert adapter.has_fatal_error is True