Using Background Tasks for Heavy Operations in FastAPI

Introduction

When building APIs, some operations like sending emails, generating reports, or processing images shouldn't block the main request-response cycle. FastAPI offers a clean and efficient way to handle such scenarios using background tasks. In this guide, you'll learn how to use them effectively, optimize performance, and avoid common pitfalls.

🧠 Related: Building a High-Performance Async API with FastAPI and PostgreSQL

Why Use Background Tasks?

Background tasks are useful for:

  • Sending confirmation or welcome emails
  • Logging analytics data
  • Generating and storing reports
  • Interacting with third-party APIs asynchronously
  • Cleaning up resources or sessions after the response is sent

Setting Up a FastAPI Project

Start by creating a FastAPI project if you haven't already:

pip install fastapi uvicorn

Create a main.py file:

from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

How Background Tasks Work

FastAPI's BackgroundTasks class allows you to schedule a function to run after the response is returned to the client. Here's a basic example:

from fastapi import FastAPI, BackgroundTasks
import time

app = FastAPI()

def send_email(email: str):
    time.sleep(5)  # Simulating delay
    print(f"Email sent to {email}")

@app.post("/register")
def register_user(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(send_email, email)
    return {"message": "User registered successfully"}

The response is sent immediately, while send_email runs in the background.

Real-World Example: Async Compatible Tasks

To avoid blocking the event loop, avoid using synchronous functions like time.sleep(). Use asyncio.sleep() instead:

import asyncio

async def async_send_email(email: str):
    await asyncio.sleep(5)
    print(f"Async email sent to {email}")

@app.post("/async-register")
def register_user(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(async_send_email, email)
    return {"message": "User registered successfully"}

FastAPI handles both sync and async functions, but using async-compatible operations ensures better concurrency.

Common Use Cases

  • Task Queues: For long-running or high-priority jobs, use task queues like Celery or RQ with Redis.
  • Notifications: Send real-time or scheduled notifications.
  • Cleanup: Release locks, remove temp files, or revoke tokens.

🔐 Related: JWT Authentication in Django and FastAPI

Gotchas and Best Practices

  • Do not use background tasks for long-running jobs (e.g. video rendering)
  • Avoid blocking calls within background functions
  • Use structured logging to capture task activity
  • Monitor errors separately, as they won’t be caught in the main request-response cycle

Cross-Framework Tip

In Django, you’d typically offload these to Celery workers or Django Q. FastAPI’s BackgroundTasks is lightweight and perfect for simple async workflows.

📘 Related: How to Prevent N+1 Query Problems in Django and FastAPI

Conclusion

Background tasks in FastAPI offer a powerful way to improve user experience and system performance by offloading non-essential work. For more advanced workflows, integrate them with external queues and monitoring.

🚀 If you're working with databases too, check out Database Connection Pooling in FastAPI with SQLAlchemy


✅ Ready to test performance, rate limiting, or background tasks? Next up: Rate Limiting and Throttling in Django and FastAPI

STAY IN TOUCH

Get notified when I publish something new, and unsubscribe at any time.