How to get all pending tasks of an event loop in Python/FastAPI?
Asked Answered
T

1

4

I am trying to understand potential slowdown in my FastAPI app.

My understanding is that each time I do an await, a task is scheduled for later, creating a backlog of task to be executed. If the process is slow for some reason, the number of pending tasks should raise. How can I monitor the number of pending tasks?

Trinl answered 13/3 at 15:9 Comment(0)
C
3

You could do that using asyncio.all_tasks(loop=None):

Returns a set of not yet finished Task objects run by the loop.

If loop is None, get_running_loop() is used for getting current loop.

As described in this article (which I would suggest having a look at):

How to Get All Asyncio Tasks

We may need to get access to all tasks in an asyncio program.

This may be for many reasons, such as:

  • To introspect the current status or complexity of the program.
  • To log the details of all running tasks.
  • To find a task that can be queried or canceled.

We can get a set of all scheduled and running (not yet done) tasks in an asyncio program via the asyncio.all_tasks() function.

For example:

# get all tasks 
tasks = asyncio.all_tasks() 

This will return a set of all tasks in the asyncio program.

It is a set so that each task is only represented once.

A task will be included if:

  • The task has been scheduled but is not yet running.
  • The task is currently running (e.g., but is currently suspended)

The set will also include a task for the currently running task, e.g., the task that is executing the coroutine that calls the asyncio.all_tasks() function.

Also, recall that the asyncio.run() method that is used to start an asyncio program will wrap the provided coroutine in a task. This means that the set of all tasks will also include the task for the entry point of the program.

Moreover, as explained in this related article, one could monitor and get details about all running tasks, in order to detect any stuck long-running tasks in the asyncio event loop, as follows:

...
# get all tasks
for task in asyncio.all_tasks():
    # log the task
    logging.debug(task)

which would return something like:

DEBUG:root:<Task pending name='Task-2' coro=<work() running at /...> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[TaskGroup._on_task_done()]>

Further, one could report the full stack trace of each task:

...
# get all tasks
for task in asyncio.all_tasks():
    # report the trace
    task.print_stack()

Finally, your understanding about async/await (coroutines) in asynchronous programming is not entirely correct, and thus, I would suggest having a look at this answer for more details.

Cochise answered 13/3 at 16:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.