## 环境 - 版本:v2.1.2(release 安装) - 平台:Linux(Arch Linux),systemd user service,`codex` 后端 - 触发场景:headless pool 高频拉起实例(`inst-headless-pool-*`) ## 现象 当某个 headless 实例的 `codex` 子进程启动链路被阻塞、永远不回 `initialize` 应答时,`launchCodexChildSession` 会**永久**阻塞在 `bootstrapHeadlessCodex`,该会话进程与其整棵子进程树全部滞留,且无任何超时或退避,新实例继续被拉起,进程数无上限堆积。 本机实测 13 小时的放大过程: 1. 用户 PATH 中的 `codex` 启动脚本(本机自建 shim,非本仓库产物)内部调用 `mise use -g codex`,该命令需要抢一个文件锁;上游排队进程达到上千后,每个新 `codex` 启动都卡在锁上,永远到不了 initialize 应答。 2. wrapper 侧 `bootstrapHeadlessCodex` 读循环(`internal/app/wrapper/app_headless.go:44`)对 `ReadBytes` 无 deadline,launch 路径(`internal/app/wrapper/app_child_session.go:52`)随之永久阻塞。三条后端链路同病:`app_headless.go`(codex)、`app_headless_claude.go`(claude)、`app_child_session_opencode.go`(opencode)。 3. 滞留进程持续累积,cgroup 任务数顶满 systemd TasksMax(本机 38071)。此后该 cgroup 内所有 `clone()` 返回 EAGAIN: - codex-remote 自身 Go runtime 直接 `fatal error: newosproc`(errno 11),实例日志中可复现; - 被拉起的外部命令全部 panic/失败(本机 mise 当日产生 527 个 SIGABRT coredump); - daemon 仍持续重试拉起,故障自我放大,持续 13 小时,直到人工重启服务。 `/proc/locks` 实测锁队列 19+ 层深;崩溃期间 cgroup `pids.current == pids.max == 38071`。 ## 根因 触发源在本机(shim 的全局写锁),但**上游缺陷是它从"局部变慢"放大为"整机资源耗尽"的原因**: 1. bootstrap 握手无超时——子进程不应答时会话进程无限滞留; 2. bootstrap 阶段不响应 ctx 取消——即使会话被要求停止也无法回收滞留中的 launch; 3. launch 失败/阻塞无退避与并发上限,资源耗尽后仍以原有频率重试,crash-loop 放大故障。 ## 建议 1. 为三个 backend 的 bootstrap 握手加超时(超时后 kill 子进程并返回错误);本机 codex app-server 正常握手在 1s 内,建议 15s 量级; 2. 让 bootstrap 阶段响应 ctx 取消; 3. (可选)launch 失败指数退避,或在检测到资源耗尽(EAGAIN)时熔断。 我可以提交一个最小修复 PR:统一封装带超时 + ctx 取消的 bootstrap 调用,三个调用点切换过去,并附回归测试。
Activity
fix(wrapper): bound child bootstrap handshake with timeout and parent…