跳转至

恢复期间结构化会话持有丢失

在仓库根目录运行:

ORCA_BACKGROUND_LAUNCH=1 node docs/audits/structured-hold-retention/reproduce.mjs

该脚本将实际的 StructuredAgentSessionHolds 实现打包为临时 CommonJS 模块,按正常方式加载它们,并删除其文件和模块缓存条目。它先在没有恢复后持有者检查的情况下运行一次代码,再使用当前源代码运行一次。它使用延迟的 provider 获取、一个隔离的假子进程,以及 5 ms 的释放宽限期。它不会启动任何应用程序、provider 或终端,也不会读取任何用户配置。

最后一个 surface 在获取挂起期间释放其持有。此时会话没有 provider 子进程,因此 release() 无法启动释放时钟。修复前,获取完成时存在一个子进程、零个持有者,且没有已调度的驱逐。修复后,成功的获取会检查存活的持有者,并调度现有的释放时钟。已记录的子进程只释放一次。

RPC 路径在 src/main/runtime/rpc/methods/structured-agent-session-hold.ts 中等待 host.hold() 之前注册连接清理。运行时套接字关闭会在 runtime-rpc/runtime-rpc-lifecycle.ts 中调用 cleanupSubscriptionsForConnection()。这提供了此处复现的生产环境中获取期间释放的顺序。

所有权限制

  • 这证明了一个生命周期竞态,而不是证明它导致了某个特定的 OOM 报告。未测量任何进程 RSS。它适用于正在获取 provider 子进程的结构化会话,而不是普通 PTY 标签页。
  • 释放时钟保留其 15 秒生产宽限期,在回合处于活动状态时等待,并在新的持有者到达时取消。获取失败保留其现有处理。
  • 处置可防止迟到的获取或释放回调重新启动时钟。主机拆除在处置之后负责清理。主机更广泛的预附加关闭准入不属于此修复范围。
  • 恢复的无子进程日志不一定被放弃。启动时选择已持久化的可见标签页;host.sessions 提供 listSessionTabs(),无子进程会话可以保留活动的 TUI 所有者。host.close() 在移除日志之前关闭该 TUI 所有者。此修复既不会驱逐无子进程历史,也不会从传输丢失推断进程退出。
  • 执行仍保留在所属运行时上,没有 wire 或 SSH 路由更改。

针对性回归测试位于 src/main/native-chat/agent-session-wire/structured-agent-session-hold-resume-race.test.ts。 它们覆盖最后一个持有者丢失、活动回合、新持有者、重连、获取失败、显式关闭和处置。

相同 ID 替换在两个所有权层都被围栏保护。持有者条目在释放并重新添加后获得新的化身,因此旧的失败获取无法移除替换项。RPC 使用订阅注册表的 releaseIfCurrent() 清理,因此其失败无法注销替换项的连接清理。重复添加仍保持为一个持有者。类测试和真实 host/RPC 测试覆盖旧失败在替换成功之前和之后到达;断开连接仍会正常释放替换项。它们还覆盖相反结果:旧获取成功,而替换项拒绝过期围栏。其最后一个持有者回滚会为已获取的子进程启动相同的回合感知释放时钟。RPC 字段或已发布帧形状均不更改。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca