FastAPI 背景任務 (Background Tasks)

有時候,你需要在 API 請求完成後執行一些耗時的操作,但你不希望使用者一直等待這些操作完成才收到回應。

例如:

  • 使用者註冊後,寄送歡迎 Email。
  • 處理完訂單後,寫入一系列的 Log 或數據分析。
  • 壓縮或轉檔上傳的圖片。

FastAPI 提供了 Background Tasks 來解決這個問題。

使用 BackgroundTasks

你需要定義一個函數 (普通函數或非同步函數皆可) 作為要在背景執行的任務。

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def write_notification(email: str, message=""):
    with open("log.txt", "a") as log:
        log.write(f"notification for {email}: {message}\n")

from typing import Annotated

@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    # 將任務加入背景佇列 (不會這時候執行,而是等 Response 回傳後才執行)
    background_tasks.add_task(write_notification, email, message="some notification")

    return {"message": "Notification sent in the background"}

流程說明

  1. 在路徑操作函數中,宣告 background_tasks: BackgroundTasks 參數。
  2. 呼叫 background_tasks.add_task(func, *args, **kwargs) 加入任務。
    • func: 要執行的函數物件。
    • *args, **kwargs: 傳給該函數的參數。
  3. 回傳 Response (return ...)。
  4. 回應發送給客戶端之後,FastAPI 會在背景執行 write_notification

依賴注入中的背景任務

你也可以在 Dependency 中使用 BackgroundTasks,FastAPI 會自動合併所有的背景任務。

from typing import Annotated
from fastapi import BackgroundTasks, Depends, FastAPI

# 假設這是你的日誌寫入函數
def write_log(message: str):
    with open("api_log.txt", "a") as log:
        log.write(message)

def get_query(background_tasks: BackgroundTasks, q: str | None = None):
    if q:
        message = f"found query: {q}\n"
        background_tasks.add_task(write_log, message)
    return q

@app.post("/send-notification-dep/{email}")
async def send_notification_dep(
    email: str,
    background_tasks: BackgroundTasks,
    q: Annotated[str | None, Depends(get_query)] = None
):
    message = f"message to {email}\n"
    background_tasks.add_task(write_log, message)
    return {"message": "Message sent"}

注意事項

雖然 BackgroundTasks 很方便,但它是在同一個 Application Process 中執行的。這意味著:

  1. 如果你的任務非常消耗 CPU (CPU bound),它可能會拖慢你的 API 效能。
  2. 如果你重新啟動伺服器,尚未執行的背景任務可能會遺失。

對於 非常繁重必須保證執行 的任務 (如影像處理、長時間爬蟲),建議使用專門的任務隊列系統,如 CeleryRedis Queue (RQ),將任務完全交給另一個 Process 或伺服器去處理。

FastAPI 的 BackgroundTasks 適合用於「輕量級、簡單」的背景作業。

總結

  • 使用 BackgroundTasks 可以在回傳回應後執行程式碼。
  • 適合寄信、寫 Log 等不需要即時回應且運算量不大的工作。
  • 對於重度任務,建議使用 Celery。