diff --git a/tier2/gen-worker/service/control_plane.py b/tier2/gen-worker/service/control_plane.py index 09151918..3bbaf908 100644 --- a/tier2/gen-worker/service/control_plane.py +++ b/tier2/gen-worker/service/control_plane.py @@ -170,8 +170,12 @@ async def _wait_for_turn_end(base_url: str, agent_id: str, session_id: str, *, print(f"[tier2-control] 订阅 SSE 等本回合结束: session={session_id} agent={agent_id} " f"(总超时 {timeout_s:.0f}s / 空闲超时 {idle_timeout_s:.0f}s)", flush=True) try: - # read=None:逐行读流不受单次读超时打断;总时长 / 空闲由本函数显式判(下方 elapsed/idle)。 - timeout_cfg = httpx.Timeout(connect=15.0, read=None, write=15.0, pool=15.0) + # read=idle_timeout_s(2026-06-24 cp-smoke-008 实证修复):此前 read=None,SSE 流【完全静默】时 + # (008:服务端 3 次 redis 超时打断了事件发布 → 既无 data 也无心跳)aiter_lines 永久 await, + # 而总/空闲超时检查写在 line 循环【体内】、无 line 进来就永不触发 → 控制面卡死 60min(实证)。 + # 把 read 设成 idle_timeout_s:静默超过它即 httpx.ReadTimeout → 下方 except 兜住 → 据 on-disk 评门继续。 + # idle_timeout_s=300s 远大于 agent 内部 run_gates(chrome ~60s)的正常静默间隙,不会误杀正常回合。 + timeout_cfg = httpx.Timeout(connect=15.0, read=idle_timeout_s, write=15.0, pool=15.0) async with httpx.AsyncClient(timeout=timeout_cfg) as http: async with http.stream("GET", url, params=params, headers=headers) as resp: if resp.status_code >= 300: