FastAPI启用reload模式后进程挂起,添加Socket.IO后应用无法自动重启
FastAPI启用reload模式后进程挂起,添加Socket.IO后应用无法自动重启
看起来你遇到了FastAPI配合Socket.IO使用reload模式时,进程卡在"Shutting down"状态无法自动重启的问题,我来帮你分析下原因和可行的解决办法:
问题根源
Uvicorn的reload模式触发重启时,需要先优雅关闭旧进程。但Socket.IO建立的是持久化的WebSocket长连接,如果有客户端还保持着连接,旧进程会一直等待这些连接主动断开,导致卡在"Shutting down"阶段无法退出。
具体解决办法
1. 给应用添加优雅关闭逻辑,主动断开所有Socket.IO连接
我们可以利用FastAPI的lifespan上下文管理器,在应用关闭时主动断开所有Socket.IO客户端连接,让旧进程能顺利退出:
首先,完善你的socket.py,添加断开事件的处理(同时修正connect事件的参数,AsyncServer的connect事件标准参数是sid, environ, auth):
from api.configs.logging import logDebug import socketio server = socketio.AsyncServer( cors_allowed_origins="*", async_mode="asgi", logger=True, engineio_logger=True, ping_interval=30, ping_timeout=60, ) @server.event async def connect(sid, environ, auth): logDebug(f"client {sid} connected") print(f"client {sid} connected") await server.emit("hello", f"you are connected with sid {sid}", to=sid) @server.event async def disconnect(sid): logDebug(f"client {sid} disconnected") print(f"client {sid} disconnected")
然后修改你的__init__.py中的LifeSpan逻辑,在关闭阶段主动清理所有Socket.IO连接:
from contextlib import asynccontextmanager @asynccontextmanager async def LifeSpan(app): # 这里是你的应用启动逻辑(如果有的话) yield # 应用关闭时,主动断开所有Socket.IO客户端 try: # 获取所有已连接的客户端sid all_connected_sids = [] for namespace_rooms in app.sio.manager.rooms.values(): all_connected_sids.extend(namespace_rooms.keys()) # 逐个断开连接 for sid in all_connected_sids: await app.sio.disconnect(sid) logDebug("All Socket.IO clients disconnected gracefully") except Exception as e: logDebug(f"Error disconnecting clients: {str(e)}") app = FastAPI( title="TRANSIT MASTER API", lifespan=LifeSpan, ) # ----mount socket------ sm = socketio.ASGIApp(server, socketio_path="socket.io") app.mount("/ws", sm) app.sio = server
2. 给Uvicorn设置优雅关闭超时
在run.py中添加timeout_graceful_shutdown参数,给旧进程设置一个强制退出的超时时间,避免无限挂起:
from api import createApp, SETTINGS app = createApp(SETTINGS()) if __name__ == "__main__": import uvicorn uvicorn.run( "run:app", port=80, host="0.0.0.0", reload=True, timeout_graceful_shutdown=10 # 10秒后强制终止旧进程 )
3. 开发环境临时小技巧
如果上面的配置还没生效,在修改代码保存前,可以手动关闭所有保持Socket.IO连接的客户端(比如浏览器标签页),这样旧进程没有了活跃连接,就能顺利关闭重启。
为什么这些方法有效?
- 主动断开所有Socket.IO连接:让旧进程不再等待客户端主动断开,能快速完成关闭流程
- 设置超时时间:给优雅关闭加了个“兜底”,超时后强制终止进程,避免无限卡住
备注:内容来源于stack exchange,提问作者KALAGA Serge Eric
相关产品推荐
相关产品推荐

