Skip to course content
Free FastAPI backend course

FastAPI for AI Backend Development

Unit 11.00: Background tasks and what they cannot promise

A background task runs after the response, in the same process, with no guarantees.

Three things it cannot promise

A task scheduled after a 202 response.

The code shows the response returning before the task has run.

from fastapi import BackgroundTasks, FastAPI
from fastapi.testclient import TestClient

app = FastAPI()
SENT = []


def send_receipt(email: str) -> None:
    SENT.append(email)


@app.post("/orders", status_code=202)
def create_order(background: BackgroundTasks) -> dict:
    background.add_task(send_receipt, "[email protected]")
    return {"status": "accepted"}


client = TestClient(app)
r = client.post("/orders")
print(f"{r.status_code} {r.json()}, receipts sent: {len(SENT)}")

print("""
The task ran after the response was sent -- in the same process. Three things
it cannot promise.

It is not durable: a restart or a crash loses it silently. It is not retried.
And it competes for the same workers, so a slow task slows real requests.

Use it for cheap, best-effort work. Anything that must happen needs a queue.
""")

It is not durable - a restart or a crash loses it with no record. It is not retried. And it competes for the same workers, so a slow task makes real requests slower.

That makes it right for cheap, best-effort work where loss is acceptable: a notification, a cache warm, a metric. Anything that must happen needs a queue.

The mistake this prevents

The mistake is using it for work that must complete - sending a receipt, charging a card, writing an audit record. It usually works, which is the problem: the failures are silent and rare enough to go unnoticed until they are counted.

Takeaway

Background tasks are best-effort, in-process and not retried. Use them only where losing the work is acceptable.