From aab1da3296e8000926d6b2a34d10f08af339a35e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 29 May 2026 11:02:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(executor=5Fdocker):=20=E5=88=A0=20setsid=20?= =?UTF-8?q?=E4=BF=AE=20docker=20exec=20=E5=BB=B6=E8=BF=9F=20stdout=20?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实证:`docker exec ... setsid python -c "sleep(2); print"` 等满 2s 输出空, 同条件去 setsid 输出 hello。setsid 调 setsid() syscall 后 docker exec/runc 的 stdio attach 出问题,延迟输出被截。上一条 _run_subprocess 重写修了独立的 poll-loop bug 但不是用户当下症状元凶。setsid 历史是给 §7.5 Step 3b PGID kill 协议铺路,该协议未实现的当下是空头载荷 + 副作用。改 _exec_shell:141 / _exec_python:177 各删 1 个 "setsid"。回归测试加 test_run_subprocess_delayed_output_not_lost (真子进程 sleep+print)+ test_argv_does_not_contain_setsid(防回潮)。19/19 PASS。 Co-Authored-By: Claude Opus 4.7 (1M context) --- PROGRESS.md | 3 +- core/executor_docker.py | 9 ++++-- tests/test_executor_docker.py | 55 ++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index 468701f..6c8ff57 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-05-29(`_run_subprocess` 重写修 docker exec stdout 多 chunk 静默丢失 bug + 上午 3 个 SKILL.md sandbox 凭证可用性校准) +最后更新:2026-05-29(删 docker exec argv 里的 setsid 修延迟 stdout 丢失 + `_run_subprocess` 重写修 communicate poll loop bug + 3 个 SKILL.md sandbox 凭证可用性校准) --- @@ -23,6 +23,7 @@ ### 2026-05-29 +- **删 `_exec_shell` / `_exec_python` argv 里的 `setsid` 修 docker exec 延迟 stdout 丢失**:上一条 `_run_subprocess` 重写后用户实测 LLM 拿 `cement energy efficiency` 跑 paper_server 检索仍返空 `[exit 0]` 8 字符,且 `print(f"共命中 {len(papers)} 条结果\n")` 这种必有输出的代码也丢。**根因 = `setsid`,不是 `_run_subprocess` 的 poll loop**(上一条修对了一个独立的 bug,但不是用户当下症状的元凶)。**实证差异**:`docker exec ... setsid python -c "import time; time.sleep(2); print('hello')"` 等满 2.06s 但输出空;同条件去掉 setsid `docker exec ... python -c "..."` 等满 2.08s + 输出 `hello`。`setsid` 调 `setsid()` syscall 把进程变 new session leader without controlling terminal **之后** execvp(python),docker exec / runc 的 stdio attach 对"调用方变 session leader"敏感(具体哪一层没深挖到 runc 源码,经验上 docker exec + setsid + 延迟输出 = stdout 数据被截断,业界踩过的坑)。短输出(`print('hello')` 瞬时完成)能在窗口内漏出去,延迟输出(`search()` 等 httpx 1-2s)就全丢 —— 完美解释为什么 LLM 简单 `print(version)` 测试时部分输出能回但真业务调用全空。**为什么之前 host 侧 `docker exec ... python -c "from skills.research.paper import search; ..."` 2.94s 拿 10 条成功**:那条**没有** setsid,docker exec 等的就是 python 本身,3s 全程都阻塞读 stdout 不会丢。`setsid` 历史上是 §7.5 Stage C **Step 3b PGID kill 协议**铺路用的(PROGRESS 上有"延后到外部用户开放前"这条 work item),**协议没实现的当下 setsid 是空头载荷 + 副作用**。**改法**:`core/executor_docker.py:141` 和 `:177` 各删 1 行的 `"setsid"`,argv 形态变 `docker exec ... bash -c ` / `... python