news 2026/9/19 15:46:36

oh-my-openagent Linux supervisor 挂起修复验收:IC-8 截止时刻、进程组终止与统计验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
oh-my-openagent Linux supervisor 挂起修复验收:IC-8 截止时刻、进程组终止与统计验证

oh-my-openagent Linux supervisor 挂起修复验收:IC-8 截止时刻、进程组终止与统计验证

【免费下载链接】oh-my-openagentOmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent

导读

本文基于 oh-my-openagent 仓库中的验收证据文档 criteria-linux.md,完整呈现 memory-run supervisor(内存运行监督进程)在 Linux 上"挂满 60000ms 超时上限"问题的五项验收标准、三臂统计实验结论,以及背后的源码级实现原理。读完本文,你将掌握该修复的验收方法论(截止时刻注入、孤儿进程检查、回归面覆盖、对抗性审计、n=60 统计验证),并能在仓库中定位对应的测试与实现代码,自行复现验收流程。

问题背景:supervisor 挂满 60 秒超时上限

oh-my-openagent 的 memory-run supervisor(实现于 memory-run-supervisor.ts)负责在受控环境中启动模型子进程、执行超时宽限与进程组终止,并最终发布运行结果(run outcome)。验收文档记录的问题是:在 Linux 上,进程终止链路曾在多组场景下整体挂满60000ms的超时上限(ceiling),而非按预期的截止时刻(deadline instant)在毫秒级完成优雅/硬性树终止。

验收环境固定为:

  • 容器镜像:oven/bun:1.3.12-debian
  • 工作区以复制方式(not bind-mounted)放入容器;
  • 源码最终版本:提交2752ad20f

验收文档将修复目标拆解为五个标准(Criterion 1–5),逐项以测试输出、孤儿进程检查和提交审计作为证据,最后以真实 Linux 上的三臂统计实验量化修复收益。

Criterion 1+2:截止时刻在 posix / win32 双平台分支上生效

第一条与第二条标准验证的是同一件事的两个平台分支:向 supervisor 注入(inject)平台分支后,优雅终止(graceful termination)与硬性树终止(hard tree termination)都必须使用被注入的绝对截止时刻(deadline instants),而不是各自重新计时或误用其他时钟源。

文档给出的验收结果:

(pass) injected posix branch ... graceful and hard tree termination use those instants [92.00ms] (pass) injected win32 branch ... graceful and hard tree termination use those instants [123.00ms] 5 pass / 0 fail Ran 5 tests across 1 file. [532.00ms]

修复后两组分支分别以92ms / 123ms完成终止流程;而修复前,同一批测试"每一侧都挂满完整的60000ms上限"(Previously each hung for the full 60000ms ceiling)。也就是说,同样的断言、同样的注入分支,超时从 60 秒级收敛到百毫秒级。

对应的测试文件是 memory-run-supervisor.ic8.test.ts,其中对IC8_PLATFORMS = ["posix", "win32"]两个平台分别运行两类用例:

  • 注入平台分支 + stubborn(抗拒退出)子进程:推进注入时钟 2000ms 后,等待posix-SIGTERM-<pid>.jsonwin32-graceful-<pid>.json落盘,再推进 3000ms 验证outcome.json被写出,且taskkill-invocation.json(非 win32 场景)不存在;
  • supervisor 被 SIGKILL 后由 bootstrap 独自执行持久化截止时刻:验证 supervisor 崩溃后,截止时刻约束仍由子进程侧的 bootstrap 强制执行。

测试基架位于 memory-run-supervisor-ic8-harness.ts:launchSupervisor通过OMO_MEMORY_SUPERVISOR_ALLOW_TEST_SEAMSOMO_MEMORY_SUPERVISOR_PLATFORMOMO_MEMORY_SUPERVISOR_CLOCK_PATH等环境变量注入平台与时钟测试缝(test seam),makeRun生成的launch.json中写死hardDeadlineAt: 2_000terminationGraceMs: 1_000,构成一个"2 秒硬截止 + 1 秒终止宽限"的受控运行。

Criterion 3:忽略 SIGTERM 的子进程在宽限到期后被进程组杀死

第三条标准覆盖一个典型的对抗场景:子进程完全忽略 SIGTERM。此时优雅终止必然失效,验收要求是——当终止宽限期(termination grace)耗尽时,整个进程组被强制杀死,且不留下孤儿进程:

(pass) #given a child that ignores SIGTERM #when termination grace expires #then the process group is killed [125.00ms] 1 pass / 0 fail orphan check (ps -eo pid,args | grep supervisor-child|child-bootstrap): NO ORPHANS

测试描述本身即验收断言(given / when / then):宽限期到期 → 进程组被杀。修复后的执行耗时为 125ms。验收还额外做了孤儿进程检查:通过ps -eo pid,args过滤supervisor-childchild-bootstrap两个角色,确认零孤儿(NO ORPHANS)。

进程组语义的实现位于 memory-run-supervisor-ic8-process-groups.ts:

  • terminateProcessGroup:POSIX 下process.kill(-pid, "SIGKILL")对整个进程组发信号;win32 下调用taskkill /pid <pid> /T /F,且 taskkill 返回非零状态或报错时失败关闭(fail closed);
  • processGroupIsAlive:通过process.kill(pid, 0)探活(win32 探单个 pid,POSIX 探-pid组 id),EPERM视为存活;
  • validateProcessGroupPid:拒绝非正整数 pid,防止误杀。

硬终止在 supervisor-process-identity.ts 的terminateSupervisorChildHard中实现:win32 走taskkillTree,POSIX 走signalSupervisorProcessGroup(pid, "SIGKILL"),即process.kill(-pid, "SIGKILL")。supervisor 进程还在exitSIGTERMSIGINT时同步执行containChild,确保自身消亡时顺带清理子进程树。

Criterion 4:macOS 回归面

由于修复涉及跨平台进程终止逻辑,验收必须确认没有破坏 macOS(darwin)这一回归面。文档给出的两处全量测试结果:

packages/memory-core : 481 pass 0 fail Ran 481 tests across 60 files. [75.54s] packages/omo-senpi/src/components/memory : 490 pass 0 fail Ran 490 tests across 90 files. [89.21s]
  • packages/memory-core:481 个测试、60 个文件,全部通过;
  • packages/omo-senpi/src/components/memory:490 个测试、90 个文件,全部通过。

两组均为 0 fail,说明 supervisor 的时钟与终止逻辑变更没有引入 macOS 回归。

Criterion 5:对修复提交的对抗性审计

第五条标准是对修复提交本身做对抗性审计(adversarial audit),防止"通过弱化测试来假装修复"的作弊路径:

  • 禁止模式检查:NONE—— 修复提交中未出现.skip/.only/xfail/ 抬高超时上限(raised ceiling);
  • 修复内容被描述为:两次有界重读(two bounded re-reads)加上事件合并(event coalescing)
  • 明确声明:未抬高上限、未跳过测试、未削弱任何断言、未移除任何 Linux 覆盖。

这一审计保证了验收结果的归因干净:性能提升来自实现修复,而非测试让步。

统计验证:n=60 三臂实验与拒绝的假设

验收文档对最核心的"注入 posix 分支的截止时刻"用例做了真实 Linux 上的三臂统计实验,每臂n=60

实验臂失败率说明
HEAD(修复前基线)11/60 = 18.3%原始实现,截止时刻偶发不触发
+ clock re-read(时钟重读)3/60 = 5.0%修复第一层:有界时钟重读
+ wait-helper fix(等待辅助修复)0/60 = 0.0%修复完整形态:两层叠加归零

从 18.3% 到 5.0% 再到 0.0%,每一层修复都带来可测量的失败率下降,最终在 60 次采样中实现零失败。

更有价值的是被测量并回退的备选假设(Rejected hypotheses measured and reverted):

假设失败率结论
cascade no-op(级联空操作)18/60被拒绝
group-target hard kill(改为对组目标硬杀)11/60被拒绝
test phase barrier(测试阶段屏障)12/60被拒绝

这三条假设与最终采用的两层修复不同:前者的失败率要么不低于基线(11/60),要么更高(18/60、12/60)。通过"先测量、后采用、失败即回退"的流程,修复方案被收敛到唯一有效组合——clock re-read + wait-helper。这一组数字也说明 Linux 上截止时刻失效是一个概率性问题(约 18% 的用例会挂满 60s),必须用统计手段而非单次偶发复现来验证。

源码级原理:有界重读与事件合并如何消灭 60s 挂起

文档所述"两次有界重读 + 事件合并"在源码中有直接对应实现,位于 supervisor-process-identity.ts 的scheduleSupervisorDeadline

该函数在测试缝启用时以注入时钟目录(OMO_MEMORY_SUPERVISOR_CLOCK_PATH)为时间源,通过目录内readdirSync解析形如<seq>-<timestamp>的文件获取当前时刻(readInjectedClock)。其核心调度逻辑为:

  1. 事件驱动:用watch(clockDir, check)监听时钟目录,时钟文件每次写入都会触发check
  2. 有界重读兜底(clock re-read):源码注释明确记录了修复动机——"check 在目录读取尚未产生有限时刻时会直接退出(bail),而跨越截止时刻的那次写入通常是最后一次写入,之后不再有任何事件到来去重试它,于是截止时刻永远不触发"。为此引入了setInterval(check, CLOCK_RECHECK_INTERVAL_MS),其中CLOCK_RECHECK_INTERVAL_MS = 25,每 25ms 主动重读一次时钟目录,使"截止时刻是否到达"取决于时钟的而非某一次目录读取是否恰好观察到写入。注释给出的实测对比是:仅靠目录事件边沿(edges)在 Linux 上是 11/60 失败,加上重读后降为 3/60——与验收文档统计完全吻合;
  3. 事件合并(event coalescing)check内部以settled标志去重,一旦某个事件或重读确认时刻已到(或 cancel 已执行),后续事件一律短路,避免同一个截止时刻被多次回调触发,也避免 cancel 后残留的 watcher/interval 再次执行回调。

两个截止时刻(scheduleSupervisorDeadline(manifest.hardDeadlineAt, ...)scheduleSupervisorDeadline(manifest.hardDeadlineAt + manifest.terminationGraceMs, ...))分别在 supervisor(memory-run-supervisor.ts)与 bootstrap(同文件runChildBootstrap)两侧各注册一份,形成双重保险:即使 supervisor 本身死亡,bootstrap 侧依然持有持久化的截止时刻(launch.json中的hardDeadlineAt),这正是 IC-8 用例"supervisor 被 SIGKILL 后由 bootstrap 单独强制截止时刻"验证的行为。

另外,outcome 的超时判定刻意不依赖"哪个进程的回调先跑",而是回读时钟(readSupervisorClockNow())并判断clockNow >= manifest.hardDeadlineAt(memory-run-supervisor.ts),避免 bootstrap 抢先结束子进程导致 supervisor 侧取消回调、从而"擦除"一个其实已被超出的截止时刻。

如何在仓库中复现与进一步阅读

  • 验收证据原文:.omo/evidence/20260812-linux-supervisor-hang/criteria-linux.md;
  • IC-8 包含性测试:memory-run-supervisor.ic8.test.ts(5 个用例,覆盖双平台注入、SIGKILL 兜底、资源清理、taskkill 失败关闭);测试默认超时IC8_WAIT_MS = 60_000,即验收文档中"60 秒上限"的出处;
  • 集成测试:memory-run-supervisor.integration.test.ts(驱动真实的 supervisor、bootstrap、模型子进程三者协作);
  • 测试基架:memory-run-supervisor-ic8-harness.ts 与 supervisor-test-signals.ts(注入时钟与文件系统状态等待);
  • 进程组原语:memory-run-supervisor-ic8-process-groups.ts;
  • 实现主体:memory-run-supervisor.ts 与 supervisor-process-identity.ts。

复现方式:在oven/bun:1.3.12-debian容器中(工作区复制进入、非 bind-mount,与验收环境一致)于仓库根目录执行上述.ic8.test.ts相关测试即可。需要说明的是:验收文档记录的2752ad20f是当时的源码基线,当前仓库已在此基础上继续演进,实际测试输出可能略有差异,但 IC-8 的验收断言与统计口径仍保持有效。

总结

这次 Linux supervisor 挂起修复的价值不在于某个单一改动,而在于一套可复制的验收闭环:以注入时钟制造确定性的截止时刻 → 以进程组语义保证硬终止无孤儿 → 以双平台与 macOS 全量测试守住回归面 → 以对抗性审计保证修复归因干净 → 以 n=60 三臂统计量化每一层收益并回退无效假设。18.3% → 5.0% → 0.0% 的失败率曲线,以及"两次有界重读 + 事件合并"最终胜出而三种备选假设被测量否决的过程,为处理同类"偶发性超时挂起"问题提供了一个可以直接借鉴的工程范式。

【免费下载链接】oh-my-openagentOmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 15:46:35

RealSense D435i 与 librealsense SDK:从测距到深度滤波的实践手册

RealSense D435i 与 librealsense SDK&#xff1a;从测距到深度滤波的实践手册 【免费下载链接】librealsense RealSense SDK 项目地址: https://gitcode.com/GitHub_Trending/li/librealsense librealsense 是 Intel RealSense 深度相机的官方 SDK&#xff0c;D435i 是…

作者头像 李华
网站建设 2026/9/19 15:45:23

Java对接快递单号识别API:原理、代码与工程实践

简介&#xff1a;面向Java开发者的快递单号自动识别接口实战资源&#xff0c;基于快递鸟&#xff08;Kdniao&#xff09;开放平台&#xff0c;解决从单一快递单号自动获取物流轨迹信息的业务需求。文档以完整代码实例逐步拆解API对接关键环节&#xff1a;使用HttpURLConnection…

作者头像 李华
网站建设 2026/9/19 15:43:36

自动控制原理线性系统校正:超前滞后与反馈复合校正设计实战

简介&#xff1a;《自动控制原理》&#xff08;第六版&#xff09;第六章“线性系统的校正方法”配套课件&#xff0c;面向自动控制原理课程学习者、考研复习者及相关专业师生&#xff0c;内容聚焦常用校正装置及其特性&#xff0c;与教材章节对应紧密。PPT围绕无源校正网络展开…

作者头像 李华
网站建设 2026/9/19 15:35:29

Claude Code 实战:TaoToken 跑通 TypeScript 仓库依赖清理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华