You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:49:50