Skip to content

[v2] v2-server 带上 ora-reaper、不再启动 host,适配 Node 直接执行 Git - #372

Open
ObsisMc wants to merge 4 commits into
ora-space:mainfrom
ObsisMc:feat/1145-v2-server-reaper
Open

ObsisMc wants to merge 4 commits into
ora-space:mainfrom
ObsisMc:feat/1145-v2-server-reaper

Conversation

@ObsisMc

@ObsisMc ObsisMc commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

Refs ora-space/circus#1145

v2,不涉及 specs。只改 v2-server/,接口契约不变,界面没有变化。

ora-space/desktop#768 已合并:Node 自己执行 Git,不再需要 ora-process-host 和 ora-process-guardian,但启动时必须能拉起 ora-reaper,拉不起来就不启动。本 PR 把固定的 desktop 推到 desktop#768 的合并提交,并让 v2-server 跟上。

改了什么

  • 资产:scripts/prepare-node.sh 的 source_commit 改为 aa21210e(desktop#768 在 main 上的合并提交);构建和记录的可执行文件从 ora-node、ora-process-host、ora-process-guardian 改成 ora-node、ora-reaper,assets.json 里的 host、guardian 换成 reaper。agentruntime 校验和传递的资产同步改掉。
  • 运行时:RuntimeOptions 去掉 Host、Guardian,加上 Reaper。运行目录里拷贝 Node(nb)和 reaper(rb),只启动 Node,不再等 host.sock,停止时只停 Node。
  • Node 配置:process.reaper_program 指向运行目录里的 rb。Node 默认找同目录下名为 ora-reaper 的文件,而运行目录用短名字,所以要显式写。host_directory、expected_uid 照旧写:新 Node 在旧 host 停掉后会删除它留下的 h 目录,旧目录都清完后再去掉这两项。
  • 残留清理:按可执行文件路径清理的名单加上 rb。Node 被强杀后,reaper 还会存活片刻。升级前的运行目录里可能还有 hb、gb 进程,名单里保留它们。
  • 停止确认:Node 可能在它正在停止的 Agent 退出之前先退出。以前 Node 之后还要停 host,这段时间足够 Agent 退出;去掉 host 后,残留检查紧跟在 Node 退出之后,偶尔会撞上还在退出的 opencode,报 execution shutdown unconfirmed(本地 9 次停止里出现 2 次,main 上没有)。现在运行目录里归属不明的进程有一个宽限期(StopGrace)自己退出,过了仍在才报错,仍然不按 cwd 杀进程。
  • 路径长度:没有 guardian 以后,运行目录里最长的路径是 Node 的控制 socket <Root>/n/control.sock。node、agentruntime 和 demo 的检查都改按它算,数据目录上限从约 23 个字符放宽到 67 个。
  • 文档和测试夹具:README.md、Taskfile.yml、internal/node/README.md、internal/nodeservices/README.md、internal/agentruntime/README.md 里对 host 和 guardian 的说明,以及真实测试里启动 host 的夹具,都已同步。

commit

  1. feat(v2-server): run Node with its reaper instead of starting the process host:资产、运行时、Node 配置和残留清理,附测试。新增真实测试 TestRealRuntimeRemovesRetiredHostDirectory,覆盖"升级前的运行目录启动后旧 host 目录被删除、每个 Node 只有一个 reaper、停止后没有残留"。
  2. feat(v2-server): bound runtime paths by the Node control socket:路径长度检查。
  3. docs(v2-server): describe the reaper in place of the process host and guardian:文档。
  4. fix(v2-server): give an exiting Agent the stop grace before calling cleanup unconfirmed:停止确认,附单测。

验证

  • go vet ./...;internal/node、internal/nodeservices、internal/agentruntime、demo 和根包的单测都通过。
  • 用 aa21210e 的 release 资产跑真实 Node 测试,task v2:node:test、task v2:node:agent:test、task v2:execution:test 都通过(第 4 个 commit 之后又跑了一遍)。跑完没有残留的 nb、rb 进程。
  • 浏览器里用 DeepSeek Flash 新建对话,都能正常收到回复(截图见运行 issue)。运行目录里没有 guardian 和 host,每个 Node 只有一个 reaper。
  • 升级:先用 main 和旧资产(dcff8afe)建项目、开一条对话,再在同一个数据目录和库上换成本 PR 启动。能正常启动,旧项目里新开的对话正常回复,两个 Node 的 w/h 都被删除;之后的停止和重启都没有残留进程。
  • 停止:修复后连续 6 次"启动 → 对话 → 停止",每次 Node 日志里都有 Agent 未确认停止,v2-server 一次也没有报 shutdown unconfirmed,也没有残留进程。

按 circus#896 的指标复测:4 核 arm64,release 构建,OpenCode 0.6.11 + DeepSeek Flash,同一提示词。每轮新建一个项目,等 10 秒后连开 4 条新对话。前两轮对话之间隔 5 秒,第三轮隔 45 秒。单位是秒,括号里是范围。

main(dcff8afe) 本 PR
Git 准备时间(workspace 段) 12.9(11.8–14.4) 1.0(0.7–2.2)
点击到看到回复:项目里的第一条对话 22.7(22.7–22.9) 11.2(10.5–11.8)
点击到看到回复:后续对话,间隔 5 秒 23.5(22.5–24.9) 13.1(10.7–14.3)
点击到看到回复:后续对话,间隔 45 秒 20.4(19.4–21.2) 10.2(9.2–12.1)
常驻的 Node 侧进程(除 Node 外) 每个 Node 1 个 host,每准备一次工作目录多 16 个 guardian(一轮共 80 个) 每个 Node 1 个 reaper
空闲时 Node 侧进程的 RSS 合计(2 个 Node) 约 205 MB 约 48 MB

…cess host

The pinned desktop moves to ora-space/desktop#768, where Node runs Git
itself and refuses to start without ora-reaper. Preparation builds and
records ora-node and ora-reaper, the runtime copies both and starts only
Node, and the configuration names the reaper by its short name in the
runtime root. host_directory stays so Node deletes the retired host's
state in roots prepared before the upgrade; cleanup still recognizes
host and guardian processes such roots may be running.
Without the guardian, Node's control socket is the longest path a
runtime root holds, so the root, Agent runtime and demo data directory
checks measure that instead of a guardian scope socket.
…leanup unconfirmed

Node can exit before an Agent it was stopping has gone. The process host
used to be stopped after Node, which gave such an Agent time to exit;
without it, the leftover check ran at once and reported the stop as
unconfirmed. Processes left in the root now get the same grace to exit
on their own, and are still never killed by working directory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant