# Bug 修复 v4 - 刷新后后端停止问题 ## 修复的问题 ### 刷新后后端直接停止,不继续执行 **原因**: 1. 页面刷新时 WebSocket 断开 2. `handle_disconnect` 检测到断开且没有其他连接 3. 设置 `stop_flags[f"user:{username}"]` 为 `True` 4. 任务检查停止标志时,会查找 `stop_flags[task_id]` 和 `stop_flags[f"user:{username}"]` 5. 发现用户级别的停止标志,任务停止执行 **解决方案**: 在 `handle_disconnect` 中检查是否有通过 REST API 创建的运行中任务。如果有,说明使用轮询模式,不应该停止任务。 ## 修改的文件 ### server/socket_handlers.py **修改前**: ```python @socketio.on('disconnect') def handle_disconnect(): username = connection_users.pop(request.sid, None) has_other_connection = False if username: for sid, user in connection_users.items(): if user == username: has_other_connection = True break task_info = get_stop_flag(request.sid, username) if isinstance(task_info, dict) and not has_other_connection: task_info['stop'] = True # 设置停止标志 # ... 取消任务 clear_stop_flag(request.sid, None) # 清理所有停止标志 ``` **修改后**: ```python @socketio.on('disconnect') def handle_disconnect(): username = connection_users.pop(request.sid, None) has_other_connection = False if username: for sid, user in connection_users.items(): if user == username: has_other_connection = True break # 检查是否有通过 REST API 创建的运行中任务 has_rest_api_task = False if username and not has_other_connection: try: from .tasks import task_manager running_tasks = [t for t in task_manager.list_tasks(username) if t.status == "running"] if running_tasks: has_rest_api_task = True debug_log(f"[WebSocket] 用户 {username} 有运行中的 REST API 任务,不停止") except Exception as e: debug_log(f"[WebSocket] 检查 REST API 任务失败: {e}") task_info = get_stop_flag(request.sid, username) # 只有在没有其他连接且没有 REST API 任务时才停止 if isinstance(task_info, dict) and not has_other_connection and not has_rest_api_task: task_info['stop'] = True # ... 取消任务 # 清理停止标志(只清理 sid 级别的,不清理 user 级别的) if request.sid in stop_flags: stop_flags.pop(request.sid, None) ``` ## 工作流程 ### 停止标志机制 **stop_flags 结构**: ```python stop_flags = { "client_sid": {"stop": bool, "task": asyncio.Task, "terminal": WebTerminal}, "user:{username}": {"stop": bool, "task": asyncio.Task, "terminal": WebTerminal}, "task_id": {"stop": bool, "task": None, "terminal": None} } ``` **查找顺序**: 1. 先查找 `stop_flags[client_sid]`(WebSocket sid 或 task_id) 2. 再查找 `stop_flags[f"user:{username}"]`(用户级别) ### WebSocket 断开流程(修复后) 1. **检测断开** - 移除 `connection_users[sid]` - 检查是否有其他连接 2. **检查 REST API 任务** - 查询 `task_manager.list_tasks(username)` - 检查是否有 `status == "running"` 的任务 - 如果有,设置 `has_rest_api_task = True` 3. **决定是否停止** - 如果有其他连接 → 不停止 - 如果有 REST API 任务 → 不停止 - 否则 → 停止任务 4. **清理停止标志** - 只清理 `stop_flags[sid]`(sid 级别) - 不清理 `stop_flags[f"user:{username}"]`(用户级别) - 避免影响 REST API 任务 ### 页面刷新流程(修复后) 1. **WebSocket 断开** - 检测到有运行中的 REST API 任务 - 不设置停止标志 - 任务继续执行 2. **页面重新加载** - 加载历史记录 - 恢复任务状态 - 启动轮询 3. **任务继续执行** - 后端任务不受影响 - 继续生成事件 - 前端轮询获取新事件 ## 关键改进 ### 1. 检测 REST API 任务 - 在 WebSocket 断开时检查是否有运行中的 REST API 任务 - 如果有,说明使用轮询模式,不应该停止 ### 2. 保护 REST API 任务 - 只有在没有其他连接且没有 REST API 任务时才停止 - 避免 WebSocket 断开影响 REST API 任务 ### 3. 精确清理停止标志 - 只清理 sid 级别的停止标志 - 不清理用户级别的停止标志 - 避免误清理 REST API 任务的停止标志 ## 测试场景 ### 1. 正常发送消息 - 发送消息 - 观察任务是否正常执行 - 观察输出是否正常 ### 2. 刷新页面(任务进行中) - 任务执行中刷新页面 - **观察后端是否继续执行** - 观察前端是否正常恢复 - 观察新内容是否正常追加 ### 3. 多次刷新 - 任务执行中多次刷新 - 观察每次刷新后任务是否继续 - 观察是否有累积的问题 ### 4. 停止任务 - 点击停止按钮 - 观察任务是否立即停止 - 观察前端状态是否正确 ## 构建 ```bash cd static npm run build ``` 构建成功! ## 最终效果 - ✅ 刷新后后端继续执行 - ✅ 前端正常恢复状态 - ✅ 新内容正常追加 - ✅ 工具块正确显示 - ✅ 流畅的输出效果(150ms 轮询) - ✅ 不重复显示内容 现在可以测试了!刷新页面后,后端应该继续执行,前端会正常恢复并显示新内容。