Many times, we need to run some application tasks without making the API consumer wait for their response. In such cases, it is a good practice to run such tasks in the background. In this post, we will learn how to use FastAPI Background Tasks.

If you are new to FastAPI, you can start with our post about getting started with FastAPI.

1 – FastAPI Background Tasks Example

There are several use cases for background tasks.

Some common examples where we can use FastAPI Background Tasks are as follows:

  • Sending notifications after our application performs a particular operation. For example, after accepting an order successfully, we may wish to send an email to the customer. Sending an email is slow and therefore, we don’t want to block the response to the order creation API.
  • Processing data files is another use case where background tasks can help. Depending on the size of the file, it might take a long time to process it. In such cases, it is better to respond with HTTP status 202 (ACCEPTED) and then continue with the processing in the background.

2 – Creating a FastAPI Background Task

FastAPI provides a special class BackgroundTasks. This comes directly from starlette.

The class itself is imported into the FastAPI library so that we can import it directly from FastAPI.

See below example:

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def write_email_log_file(email_id: str, message=""):
    with open("email_log.txt", mode="w") as email_file:
        email_log_entry = f"Email triggered for {email_id}: {message}"
        email_file.write(email_log_entry)

@app.post("/send-email/{email_id}")
async def generate_email(email_id: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(write_email_log_file, email_id, message="This is a background task")
    return {"message": "Email Log Entry Created by Background Task"}

Let’s understand what is going on here.

  • We first import the necessary FastAPI function and BackgroundTasks from the fastapi library.
  • After creating the app object, we define a function write_email_log_file(). This is basically a task function. It simply creates a file and places a log entry within the file simulating the process of sending an email. We want to run this function as a background task.
  • Next, we implement a request handler. It receives an email id as a path parameter. However, it also takes a parameter of type BackgroundTasks as input. FastAPI will automatically create an instance of BackgroundTasks and make it available to our request handler method.
  • Within the request handler function, we use add_task() function to add a background task. The add_task() function receives the task function (write_email_log_file) as one of the inputs. It basically signifies that the given task function needs to be executed for this background task. The other arguments are email_id and message.

3 – BackgroundTasks with Dependency Injection

BackgroundTasks also works with dependency injection. In other words, we can use a parameter of type BackgroundTasks at multiple levels within the code.

FastAPI will make sure to use the same instance. Basically, this allows us to merge all background tasks and execute them one by one.

See below example:

from fastapi import BackgroundTasks, Depends, FastAPI

app = FastAPI()

def write_email_log_file(message:str):
    with open("email_log.txt", mode="a") as email_file:
        email_file.write(message)

def create_log(background_tasks: BackgroundTasks, log: bool):
    if log:
        message = f"Logging email sent\n"
        background_tasks.add_task(write_email_log_file, message)

@app.post("/send-email-with-log/{email_id}")
async def send_email_with_log(email_id: str, background_tasks: BackgroundTasks, log: bool = Depends(create_log)):
    message = f"Hello, World to {email_id}\n"
    background_tasks.add_task(write_email_log_file, message) 
    return {"message": "Email sent"}

Basically, here the logs will be written to file email_log.txt. If the value of log is true, the create_log() function will be executed. It will add a background task. Next, we add another task in the request handler itself using the email_id parameter.

In both the cases, FastAPI shares the same object of BackgroundTasks. Basically, it uses dependency injection to create a single object. This allows us to merge the background tasks and pass them on for execution.

For more details about dependency injection, you can check out this post on dependency injection in FastAPI.

Conclusion

With this, we have successfully created an example of FastAPI Background Task.

The only caveat here that for heavy background processes, we should look at something like Celery. Basically, Celery can allow us to run background tasks in different process. However, there will be no sharing of memory and variables. More on that in a future post.

If you have any comments or queries about this post, please feel free to mention them in the comments section below.

Categories: BlogFastAPI

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *