FastApi退出时卡在等待后台任务完成的问题求助
解决FastAPI+Redis WebSocket退出时的警告与CancelledError问题
问题根源
服务器退出时,WebSocket端点中的while True循环仍在阻塞等待Redis Pub/Sub消息,且未处理asyncio.CancelledError异常,导致后台任务无法正常终止,触发警告和回溯信息。原代码仅捕获了WebSocketDisconnect,未处理服务器关闭时的任务取消信号。
修复方案
1. 添加CancelledError异常捕获
在WebSocket端点的异常处理中加入对asyncio.CancelledError的捕获,确保任务被取消时能妥善清理Redis订阅和WebSocket连接。
2. 优化Redis Pub/Sub消息监听逻辑
改用pubsub.listen()替代get_message(),配合异步迭代器更优雅地处理消息,同时便于响应取消信号。
修改后的WebSocket端点代码
import asyncio from fastapi import WebSocket, WebSocketDisconnect @app.websocket("/ws/{user_id}") async def websocket_endpoint(websocket: WebSocket, user_id: str): await manager.connect(websocket) channel_name = f"channel_{user_id}" async with redis.pubsub() as pubsub: await pubsub.subscribe(channel_name) try: # 使用异步迭代器监听消息,响应取消信号更及时 async for message in pubsub.listen(): if message["type"] == "message": decoded_message = message["data"].decode("utf-8") await manager.send_personal_message(decoded_message, websocket) except WebSocketDisconnect: manager.disconnect(websocket) except asyncio.CancelledError: # 处理任务取消信号,清理资源 manager.disconnect(websocket) await pubsub.unsubscribe(channel_name) finally: # 确保无论何种情况都断开连接和取消订阅 if not websocket.client_state.disconnected: manager.disconnect(websocket) await pubsub.unsubscribe(channel_name)
额外优化建议
- 在FastAPI应用中配置关闭事件,主动关闭所有Redis连接,避免资源泄漏:
@app.on_event("shutdown") async def shutdown_event(): await redis.close() await redis.wait_closed()
原理说明
async for message in pubsub.listen()会自动响应异步任务的取消信号,当服务器关闭时,任务被取消会触发CancelledError,此时我们可以在异常处理块中完成资源清理。- 新增的
finally块确保无论正常退出还是异常退出,都能断开WebSocket连接并取消Redis订阅,避免后台任务残留。
内容的提问来源于stack exchange,提问作者nehat khan
相关产品推荐
相关产品推荐

