diff --git a/changes/unreleased/4880.42PW26hGpLypMJMxTeiQZ6.toml b/changes/unreleased/4880.42PW26hGpLypMJMxTeiQZ6.toml new file mode 100644 index 00000000000..fdcc0952a37 --- /dev/null +++ b/changes/unreleased/4880.42PW26hGpLypMJMxTeiQZ6.toml @@ -0,0 +1,6 @@ +internal = "Improve Internal Logic for Network Retries" + +[[pull_requests]] +uid = "4880" +author_uid = "Bibo-Joshi" +closes_threads = ["4871"] diff --git a/src/telegram/ext/_updater.py b/src/telegram/ext/_updater.py index c67d147d6d0..4fbf82128b4 100644 --- a/src/telegram/ext/_updater.py +++ b/src/telegram/ext/_updater.py @@ -335,7 +335,7 @@ async def _start_polling( _LOGGER.debug("Bootstrap done") - async def polling_action_cb() -> bool: + async def polling_action_cb() -> None: try: updates = await self.bot.get_updates( offset=self._last_update_id, @@ -352,7 +352,7 @@ async def polling_action_cb() -> bool: "Received data was *not* processed!", exc_info=exc, ) - return True + return if updates: if not self.running: @@ -365,7 +365,7 @@ async def polling_action_cb() -> bool: await self.update_queue.put(update) self._last_update_id = updates[-1].update_id + 1 # Add one to 'confirm' it - return True # Keep fetching updates & don't quit. Polls with poll_interval. + return def default_error_callback(exc: TelegramError) -> None: _LOGGER.exception("Exception happened while polling for updates.", exc_info=exc) @@ -678,14 +678,13 @@ async def _bootstrap( :paramref:`max_retries`. """ - async def bootstrap_del_webhook() -> bool: + async def bootstrap_del_webhook() -> None: _LOGGER.debug("Deleting webhook") if drop_pending_updates: _LOGGER.debug("Dropping pending updates from Telegram server") await self.bot.delete_webhook(drop_pending_updates=drop_pending_updates) - return False - async def bootstrap_set_webhook() -> bool: + async def bootstrap_set_webhook() -> None: _LOGGER.debug("Setting webhook") if drop_pending_updates: _LOGGER.debug("Dropping pending updates from Telegram server") @@ -698,7 +697,6 @@ async def bootstrap_set_webhook() -> bool: max_connections=max_connections, secret_token=secret_token, ) - return False # Dropping pending updates from TG can be efficiently done with the drop_pending_updates # parameter of delete/start_webhook, even in the case of polling. Also, we want to make diff --git a/src/telegram/ext/_utils/networkloop.py b/src/telegram/ext/_utils/networkloop.py index 41de1b44c0a..e59f12229db 100644 --- a/src/telegram/ext/_utils/networkloop.py +++ b/src/telegram/ext/_utils/networkloop.py @@ -54,10 +54,12 @@ async def network_retry_loop( ) -> None: """Perform a loop calling `action_cb`, retrying after network errors. - Stop condition for loop: - * `is_running()` evaluates :obj:`False` or - * return value of `action_cb` evaluates :obj:`False` + Stop condition for loop in case of ``max_retries < 0``: + * `is_running()` evaluates :obj:`False` * or `stop_event` is set. + + Additional stop condition for loop in case of `max_retries >= 0``: + * a call to `action_cb` succeeds * or `max_retries` is reached. Args: @@ -86,12 +88,14 @@ async def network_retry_loop( * > 0: Number of retries. """ + infinite_loop = max_retries < 0 log_prefix = f"Network Retry Loop ({description}):" effective_is_running = is_running or (lambda: True) - async def do_action() -> bool: + async def do_action() -> None: if not stop_event: - return await action_cb() + await action_cb() + return action_cb_task = asyncio.create_task(action_cb()) stop_task = asyncio.create_task(stop_event.wait()) @@ -104,16 +108,20 @@ async def do_action() -> bool: if stop_task in done: _LOGGER.debug("%s Cancelled", log_prefix) - return False + return - return action_cb_task.result() + # Calling `result()` on `action_cb_task` will raise an exception if the task failed. + # this is important to propagate the error to the caller. + action_cb_task.result() _LOGGER.debug("%s Starting", log_prefix) cur_interval = interval retries = 0 while effective_is_running(): try: - if not await do_action(): + await do_action() + if not infinite_loop: + _LOGGER.debug("%s Action succeeded. Stopping loop.", log_prefix) break except RetryAfter as exc: slack_time = 0.5 diff --git a/tests/ext/test_application.py b/tests/ext/test_application.py index d30d7d845a0..3d6631c0f16 100644 --- a/tests/ext/test_application.py +++ b/tests/ext/test_application.py @@ -1716,6 +1716,7 @@ def thread_target(): expected = { name: name for name in updater_signature.parameters if name != "error_callback" } + expected["bootstrap_retries"] = 42 thread = Thread(target=thread_target) thread.start() app.run_polling(close_loop=False, **expected) @@ -2022,6 +2023,7 @@ def thread_target(): assert self.received[name] == param.default expected = {name: name for name in updater_signature.parameters if name != "self"} + expected["bootstrap_retries"] = 42 thread = Thread(target=thread_target) thread.start() app.run_webhook(close_loop=False, **expected)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: