Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

FastAPI: Background outside of route functions behaves differently?

In FastAPI, I’m trying to understand why the background instance not getting created outside the route function handler and its different behaviors.

Examples:

Standard doc example working as expected:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@app.get('/')
async def index(background_tasks: BackgroundTasks):
    background_tasks.add_task(some_function_reference)
    #Executes non-blocking in the same asyncio loop without any issues
    return "Hello"

It behaves differently when adding the background_tasks outside of the route function:

async def some_logic(background_tasks: BackgroundTasks):
    #Throws a "required positional argument missing" error
    background_tasks.add_task(some_function_reference)


@app.get('/')
async def index():
    await some_logic()
    #Executes non-blocking in the same asyncio loop
    return "Hello"

meanwhile, if we try to init the BackgroundTasks in the some_logic function, the task does not run as following:

async def some_logic():
    #Does not Run
    background_tasks = BackgroundTasks()
    background_tasks.add_task(some_function_reference)


@app.get('/')
async def index(background_tasks: BackgroundTasks):
    await some_logic()
    #Executes non-blocking in the same asyncio loop
    return "Hello"

Why would these three cases be different? Why do i need to pass the background tasks from the route function to the following called function?

>Solution :

The BackgroundTasks instance gets populated by the FastAPI framework and injected into the callers. In the first example, you use a route which has it’s dependencies injected by FastAPI.

The second example, you are calling some_logic as a normal function. Because it’s not being called by FastAPI directly, no dependency injection is happening.

In the third example, you create a new instance of background tasks, but this is a different instance than the one that FastAPI cares about. You create tasks in it, but there is no handler registered to act on them.

In this case, if the goal is to make the background tasks easier to apply to methods, you could add the some_logic function as a dependency of the route. A dependency is called by FastAPI, and therefore the arguments will be injected.

Example:

from fastapi import FastAPI, Depends
from starlette.background import BackgroundTasks
from starlette.testclient import TestClient

app = FastAPI()


def task():
    print("Hello from the Background!")


async def some_logic(background_tasks: BackgroundTasks):
    background_tasks.add_task(task)


@app.get('/', dependencies=[Depends(some_logic)])
async def index():
    return "Hello"


with TestClient(app) as client:
    client.get("/")
Hello from the Background!
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading