FastAPI优雅停机时如何终止后台任务?
解决FastAPI --reload模式下优雅关闭的死锁问题
问题根源
当用uvicorn --reload启动FastAPI时,Uvicorn的优雅关闭流程是这样的:
- 停止接收新请求
- 关闭现有连接
- 等待所有后台任务完成
- 执行
lifespan上下文管理器中yield后的 shutdown 逻辑
你的场景里,后台任务依赖Session.close_all()才能结束,但这个调用又要等后台任务完成后才会执行,直接形成死锁,导致"Shutting down sessions"日志永远无法输出。
可行解决方案
1. 提前注册信号处理器,优先执行会话关闭
在应用启动时注册信号监听,当收到Uvicorn发送的终止信号(SIGTERM)时,先调用Session.close_all()让后台任务正常退出,再继续后续关闭流程。
示例代码:
import asyncio import signal from fastapi import FastAPI from contextlib import asynccontextmanager class Session: _active_sessions = [] @classmethod def close_all(cls): cls._active_sessions.clear() print("All sessions closed") @asynccontextmanager async def lifespan(app: FastAPI): # 定义信号处理函数 def handle_shutdown_signal(): Session.close_all() # 注册SIGTERM/SIGINT信号处理器 loop = asyncio.get_running_loop() for sig in (signal.SIGTERM, signal.SIGINT): loop.add_signal_handler(sig, handle_shutdown_signal) yield # 此时后台任务已结束,shutdown逻辑可正常执行 print("Shutting down sessions") app = FastAPI(lifespan=lifespan) # 示例后台任务 @app.get("/start-task") async def start_task(): async def background_task(): while Session._active_sessions: await asyncio.sleep(1) asyncio.create_task(background_task()) return {"status": "task started"}
2. 给后台任务添加退出检测
修改后台任务逻辑,让它定期检查全局关闭标记,当标记触发时主动退出,无需等待Session.close_all()被动结束。
示例代码:
import asyncio from fastapi import FastAPI from contextlib import asynccontextmanager shutdown_flag = asyncio.Event() class Session: _active_sessions = [] @classmethod def close_all(cls): cls._active_sessions.clear() shutdown_flag.set() @asynccontextmanager async def lifespan(app: FastAPI): yield print("Shutting down sessions") Session.close_all() app = FastAPI(lifespan=lifespan) @app.get("/start-task") async def start_task(): async def background_task(): while not shutdown_flag.is_set(): await asyncio.sleep(1) asyncio.create_task(background_task()) return {"status": "task started"}
3. 开发环境临时方案
如果只是开发阶段用--reload,可以直接按两次CTRL+C强制关闭,但这仅作为临时手段,生产环境必须使用前面的优雅关闭方案。
注意事项
--reload是为开发场景设计的,生产环境建议关闭该选项,直接使用Uvicorn默认的优雅关闭流程- 所有后台任务都应设计为可中断的,避免依赖外部触发才能退出
内容的提问来源于stack exchange,提问作者okay
相关产品推荐
相关产品推荐

