Skip to content

[v2] 预热项目 Node 并回收空闲的 Node - #354

Open
ObsisMc wants to merge 4 commits into
ora-space:mainfrom
ObsisMc:perf/1028-v2-prewarm-node
Open

ObsisMc wants to merge 4 commits into
ora-space:mainfrom
ObsisMc:perf/1028-v2-prewarm-node

Conversation

@ObsisMc

@ObsisMc ObsisMc commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator

Refs ora-space/circus#1028

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

改了什么

  • 预热:项目经 API 创建成功后,在后台为它起 Node,创建请求不等。服务启动时先起 Demo,再按最近活动(最新对话的创建时间,没有对话时取项目创建时间)依次预热,最多 V2_NODE_IDLE_MAX 个,一次一个。
  • 复用:对话的 runtime 阶段遇到已就绪的 Node 时,直接复用并标记 reused。Node 还在预热时,会话等同一个 Node,不会再起第二个。
  • 预热失败:失败不影响项目创建。之后的会话会先确认失败的 Node 已停止,再自己冷启动一次;会话自己发起的冷启动失败不重试,和原来一样。
  • 空闲回收:没有会话占用、没有进行中的 Node 命令、也没有调用方正要占用时,Node 才算空闲。空闲超过 V2_NODE_IDLE_TIMEOUT(默认 60m)的停止;空闲 Node 超过 V2_NODE_IDLE_MAX(默认 3)个时,先停最久没用的。Demo 不回收。
    • 停止得不到确认时,Node 保留登记,同一目录不会起第二个 Node。
    • 回收后不自动重起,下一个会话冷启动。
    • 空闲的 Node 崩溃后,下一个会话起新的。
  • Skill:Node 预热上线后就应用市场 Skill。Node 被回收后,等它下次上线再应用。正在应用的 Node 不会被回收。

规则和默认值的依据写在 v2-server/README.md 的「项目 Node 的预热与回收」一节。

commit

  1. perf(v2): prewarm project Nodes and reclaim idle ones:agentruntime 的预热、复用、失败兜底和回收,附单测。
  2. feat(v2): list projects by latest activity for prewarming:store.RecentProjects。
  3. feat(v2): announce projects created through the API:server.Options.ProjectCreated。
  4. perf(v2): prewarm Nodes at startup and after project creation:main 里的接线、两个环境变量和 README。

实测

条件:OpenCode + DeepSeek Flash,同一任务,各 3 轮,取中位数。建完项目等 10 s 再开对话;每轮结束删除对话、再停 30 s;两边都用新库和新数据目录。单位是秒。

阶段 基线(当时的 main) 本 PR
runtime 2.3 0.0(复用)
workspace 13.0 13.2
plugin 2.0 2.0
agent 4.0 4.4
response 3.1 2.6
首条输出 25.0(24.4–25.0) 22.2(21.8–22.3)
  • 建完项目立刻开对话时,runtime 段仍有 2.7 s,会话要等剩下的预热时间。
  • 把 V2_NODE_IDLE_TIMEOUT 设成 20s 验证回收:被回收的项目再开对话时冷启动,runtime 2.2 s,首条输出 23.6 s。
  • 每次停服务后,按可执行文件路径检查,没有残留的 Node 进程。

验证

  • 单测:
    • internal/agentruntime(带 -race):新增 12 个预热、回收用例,覆盖预热失败、预热中开对话、回收后开对话。
    • internal/store:TestRecentProjectsOrdersByLatestConversationThenCreation,用 TEST_DATABASE_URL 跑。
    • internal/server:TestProjectRepositoryLifecycle。
    • v2-server:TestNodeIdlePolicy。
    • 以上全部通过。
  • 没跑完整的 cloud 测试套件,也没跑 e2e。

A project's Node can now be started ahead of its first session (Warm). A
session arriving meanwhile waits for that same Node; if the prewarm fails,
the session confirms it stopped and cold-starts once itself. A Node already
up marks the runtime preparation stage as reused.

Idle Nodes (no workspace owner, no Node command in flight, no caller about
to own one) stop after IdleTimeout (default 60m); beyond MaxIdle (default
7) the least recently used stop first. The Demo Node is exempt, a Node
still starting is not counted, and one whose stop is unconfirmed stays
registered so no second incarnation starts in its directory.
RecentProjects orders projects across tenants by their latest chat
conversation, or their creation when they have none.
server.Options.ProjectCreated is told about each stored project, so main
can prewarm its Node without the creation request waiting.
Startup warms the Demo first, then the most recently active projects up to
V2_NODE_IDLE_MAX, one at a time; a created project is warmed in the
background. V2_NODE_IDLE_TIMEOUT and V2_NODE_IDLE_MAX tune idle reclaim.
The README describes prewarming and the reclaim policy.
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