FastAPI Lifespan Events:管理應用程式啟動與關閉的生命週期
在開發 Web 應用程式時,我們經常需要在程式 「啟動前」 執行一些初始化操作(例如:建立資料庫連線池、載入機器學習模型),並在程式 「關閉時」 執行資源釋放(例如:清理快取、關閉連線)。
FastAPI 提供了一個現代化且簡單的方式來處理這些需求:Lifespan Events。
什麼是 Lifespan?
Lifespan 指的是應用程式從「開始運行」到「結束運行」的整個週期。
在早期的 FastAPI 版本中,我們使用的是 startup 和 shutdown 事件處理器。雖然它們依然可用,但現在更推薦使用 lifespan 參數,因為它基於 Python 的 非同步上下文管理器 (Async Context Manager),能更優雅地處理資源的生命週期,且支援跨多個版本的一致性。
如何使用 Lifespan?
我們需要定義一個使用 @asynccontextmanager 裝飾的非同步函式,並將其傳遞給 FastAPI 實例的 lifespan 參數。
基本範例
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# --- 這裡寫程式啟動前的邏輯 ---
print("應用程式正在啟動,準備初始化資源...")
db_connection = "Connected" # 模擬資源初始化
yield # 程式會在這裡暫停,開始接收 Request 的處理流程
# --- 這裡寫程式關閉前的邏輯 ---
print("應用程式正在關閉,釋放資源中...")
db_connection = "Disconnected"
print(f"資料庫狀態: {db_connection}")
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def read_root():
return {"message": "Hello World"}
yield之前:在應用程式開始處理任何 Request 之前執行。yield之後:在應用程式完全處理完請求並準備關閉時執行。
實戰應用:管理資料庫連線池
在生產環境中,頻繁地開啟和關閉資料庫連線效能很差。使用 Lifespan 可以讓我們在啟動時建立一個全域的連線池。
from contextlib import asynccontextmanager
from fastapi import FastAPI
# 假設這是一個虛擬的資料庫套件
class Database:
async def connect(self):
print("連線到資料庫池...")
async def disconnect(self):
print("關閉資料庫池...")
db = Database()
@asynccontextmanager
async def lifespan(app: FastAPI):
# 啟動時連線
await db.connect()
yield {"db": db} # 也可以將資源傳遞給 app.state (選用)
# 關閉時斷開
await db.disconnect()
app = FastAPI(lifespan=lifespan)
載入大型資源 (如 ML 模型)
如果你正在開發一個處理圖片辨識或 NLP 的 API,載入模型可能需要好幾秒鐘。將其放在 Lifespan 中可以避免第一個 User 請求時才在載入的延遲感。
import torch # 範例
from contextlib import asynccontextmanager
from fastapi import FastAPI
ml_models = {}
@asynccontextmanager
async def lifespan(app: FastAPI):
# 啟動時載入重量級模型到記憶體(或 GPU)
print("Loading ML models...")
ml_models["sentiment_analysis"] = torch.load("model.pth")
yield
# 關閉時清理
ml_models.clear()
app = FastAPI(lifespan=lifespan)
為什麼 Lifespan 比 Startup/Shutdown 好?
- 結構清晰:初始化與清理邏輯寫在同一個函式中,容易閱讀且不容易漏掉清理步驟。
- 異常處理:可以使用標準的
try...finally...來確保資源即使發生錯誤也會被釋放。 - 效能:基於
anyio或asyncio的底層優化,執行更高效。
如果你還在使用舊專案中的
@app.on_event("startup"),雖然它目前還能跑,但官方強烈建議未來轉換到 lifespan 方式,因為舊有的 on_event 已經被官方標註為 Deprecated(棄用)。