-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
Bug Description
In the asynchronous polling loop of AsyncTeleBot (e.g., inside telebot.AsyncTeleBot._process_polling), incoming updates are dispatched to process_new_updates using asyncio.create_task(). However, the resulting asyncio.Task object is not assigned to any variable or collection, meaning no strong reference is kept. (See below code block, also see here)
try:
while self._polling:
try:
updates = await self.get_updates(offset=self.offset, allowed_updates=allowed_updates, timeout=timeout, request_timeout=request_timeout)
if updates:
self.offset = updates[-1].update_id + 1
# noinspection PyAsyncCall
asyncio.create_task(self.process_new_updates(updates)) # Seperate task for processing updates
if interval: await asyncio.sleep(interval)
error_interval = 0.25 # drop error_interval if no errorsAccording to the official Python asyncio documentation, the event loop only maintains weak references to tasks. If a task yields control back to the event loop (e.g., awaiting network I/O or a sleep), Python's Garbage Collector (GC) may destroy the unreferenced task mid-execution. This results in the task disappearing silently without raising any exceptions.
I also copy the official explanation from Python documentation (https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) here to better illustrate the risk:
Important: Save a reference to the result of this function, to avoid a task disappearing mid-execution. The event loop only keeps weak references to tasks. A task that isn’t referenced elsewhere may get garbage collected at any time, even before it’s done. For reliable “fire-and-forget” background tasks, gather them in a collection:
Potential Solution
Add a queue to AsyncTeleBot to store asyncio.Task created via asyncio.create_task() is enough to solve the problem.
If it is ok, I would be happy to create a PR to fix it.