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"}
流程說明
- 在路徑操作函數中,宣告
background_tasks: BackgroundTasks參數。 - 呼叫
background_tasks.add_task(func, *args, **kwargs)加入任務。func: 要執行的函數物件。*args,**kwargs: 傳給該函數的參數。
- 回傳 Response (
return ...)。 - 回應發送給客戶端之後,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 中執行的。這意味著:
- 如果你的任務非常消耗 CPU (CPU bound),它可能會拖慢你的 API 效能。
- 如果你重新啟動伺服器,尚未執行的背景任務可能會遺失。
對於 非常繁重 或 必須保證執行 的任務 (如影像處理、長時間爬蟲),建議使用專門的任務隊列系統,如 Celery 或 Redis Queue (RQ),將任務完全交給另一個 Process 或伺服器去處理。
FastAPI 的 BackgroundTasks 適合用於「輕量級、簡單」的背景作業。
總結
- 使用
BackgroundTasks可以在回傳回應後執行程式碼。 - 適合寄信、寫 Log 等不需要即時回應且運算量不大的工作。
- 對於重度任務,建議使用 Celery。