# 修复 Worker 单副本重启 500:优雅处理「副本未响应管理指令」 ## 摘要 单副本重启端点 `POST /api/v1/admin/workers/restart` 在目标 worker 不在线/无 `__admin__` 管理能力时,`_send_admin_cmd` 抛 `RuntimeError`,端点未捕获,被全局异常处理器记录后 re-raise,最终 ASGI 返回 500 并伴随 `net::ERR_FAILED`。需让该端点对「未响应/不在线/运行旧版」返回明确的非 500 结构化错误,同时改进错误文案以便运维定位。 ## 现状分析 - [worker_admin.py](file:///home/chakcy/chongming-zenoh/src/chongming/app/routes/worker_admin.py#L60-L80):`restart_worker` 直接 `await manager.restart_worker(...)`,无 try/except。对比 `restart_all`(L107 已捕获单副本失败不中断)、`update_worker_config`(L169-178 已捕获映射 4xx),唯独单副本端点无兜底。 - [worker_manager.py](file:///home/chakcy/chongming-zenoh/src/chongming/app/core/worker_manager.py#L507-L553):`_send_admin_cmd` 在 Zenoh QUERY 超时/无回复时 `raise RuntimeError("副本 / 未响应管理指令(可能不在线)")`(L544-547)。 - [__init__.py](file:///home/chakcy/chongming-zenoh/src/chongming/app/__init__.py#L244-L255):全局处理器仅记录 `logger.error(f"全局异常: {exc}")` 后 re-raise → 500。 - 底层:报错实例 `worker_id=worker-0-52047` 是**旧版命名**(`worker--`,无 epoch 段)。新版 runtime 才生成 `worker---` 并声明 `__admin__`。故该副本极可能仍运行**旧版 chongming_worker**(未加载管理能力),管理层才会未响应。 ## 变更方案 ### 1. 单副本重启端点兜底 [worker_admin.py](file:///home/chakcy/chongming-zenoh/src/chongming/app/routes/worker_admin.py) - 在 `restart_worker` 中 `try: result = await manager.restart_worker(...)`。 - `except Exception as e:`(noqa BLE001)→ `logger.warning(...)` 记录;若错误含「未响应/不在线」,抛 `HTTPException(status_code=502, detail=f"重启失败: {e}(该副本可能不在线或运行旧版 Worker,未加载管理能力,请先以新版重启其进程)")`;其余错误保持映射 502/500 语义(统一用 502 + detail=str(e) 即可)。 - 效果:不再触发全局异常 handler / ASGI 500;前端 `restartOne` 已在其 catch 中 `ElMessage.error` 展示 `detail`,用户得到明确提示。 ### 2. 优化下发错误文案 [worker_manager.py](file:///home/chakcy/chongming-zenoh/src/chongming/app/core/worker_manager.py) - 将 L545-547 的超时错误文案改为: `"副本 {worker_type}/{worker_id} 未响应管理指令(可能不在线,或该 Worker 运行旧版运行时未声明 __admin__ 管理能力)"` - 便于网关日志与前端 detail 直接反映根因。 ### 3. 前端(可选,本次不强制改) - `restartOne` 已能在非 2xx 时展示后端 `detail`,无需改动。仅确认错误提示文案来自后端 detail 即可。 ## 假设与决策 - 「未响应」属**预期可解释的失败**,应返回 5xx(502)而非 200+ok:false:前端只对非 2xx 弹错,保持「消息清晰」。 - 不修改全局异常处理器:它是通用兜底,无需为此特化。 - 不修改 alive 判定/列表逻辑:`alive=true` 仅代表 liveliness token 存在,无法区分旧版进程;根因修复依赖「用新版 runtime 重启 worker 进程」,属运维动作,不写代码。 ## 验证步骤 1. `.venv/bin/python -m py_compile src/chongming/app/routes/worker_admin.py src/chongming/app/core/worker_manager.py`。 2. 重启网关(让其加载 CORS 与最新代码)。 3. 用仍为旧版命名/未响应的 worker(如 `aibox_sophon_adapter/worker-0-52047`)调用 `POST /api/v1/admin/workers/restart?worker_type=aibox_sophon_adapter&worker_id=...`: - 期望返回 JSON `{"detail":"重启失败: 副本 ... 未响应管理指令 ... 请先以新版重启其进程"}` 且 HTTP 502,不再打印「全局异常」,前端弹明确错误。 4. 对在线且加载新版 runtime 的 worker 重启,验证仍返回 `{"success":true}`(未破坏正常路径)。 5. `cd src/chongming-web && npx vue-tsc --noEmit`(如需改前端才跑;本次预计无前端改动)。 6. (可选)确认 Worker 管理重启按钮不再触发浏览器 `net::ERR_FAILED`,而是展示后端错误消息。 ## 前置/运维提示(不写代码) - 要让 `aibox_sophon_adapter` 等 external worker 能被单副本精细化管理(重启/停止/config_set),需用本项目最新 `chongming-worker`(`uv pip install -e utils/worker` 已确保)**重启该 worker 进程**,使其加载新版 runtime 并声明 `worker///__admin__`。