fix: auto-suspend oversized bot sessions - #722
Conversation
Add an opt-in per-bot maxSessionRssMiB guard that periodically samples live session process trees and suspends idle, resumable sessions when a single session exceeds its configured RSS budget. This gives operators a way to contain runaway CLI memory use before the host reaches Docker or global OOM. Co-authored-by: TRAE CLI <noreply@bytedance.com>
deepcoldy
left a comment
There was a problem hiding this comment.
对抗复审结论:请求修改。adopt / restore 本身没有发现可触发的正确性 bug,但 attestation 覆盖存在 1 处 blocker。
[P2 / blocker] Herdr 的 CLI 内存长期漏算;首个 worker 还可能把共享 Herdr host 错算给单个会话
位置:src/core/session-rss-guard.ts:65-67
这里把会话归因定义为 worker 子树 + localProcessAttestation.cliPid 子树。这个前提在 managed Herdr 上不成立:
HerdrBackend.getChildPid()只是返回this.cliPid ?? null(src/adapters/backend/herdr-backend.ts:704-706),但 managed Herdr 的 spawn 路径从未给cliPid赋值。- 因此 worker 在
src/worker.ts:9317-9318上报的是不含 CLI pid 的 attestation;后面的 25 次 late retry 仍调用同一个永远为 null 的 getter,约 3 秒后停止。 - managed Herdr agent 跑在机器共享的
botmuxHerdr host 下。host 已存在时,它不是当前 worker 的后代,所以 guard 永远只算 worker Node,自身 CLI 即使远超阈值也不会休眠。 - 反过来,若当前 worker 恰好是首次创建共享 host 的那个 worker,detached/unref 并不会立刻改变 PPID;worker 子树会暂时包含共享 host 及其中其它 session 的 agent,可能把多会话内存全算到一个逻辑会话上并休眠错误对象。worker/daemon 重启后 host reparent,又退化成永久漏算。
所以 “attest 尚未上报” 不只是一个短窗口:Herdr 是稳定可复现的永久缺口。Zellij 也有同类 fail-open 风险:CLI pid 若在约 3 秒预算后才可解析,之后不再补 attestation,后续每轮都漏算;即使最终能在 3 秒内解析,期间碰到 60 秒 timer 也会漏掉当轮。
建议合并前:
- 对每个允许 RSS auto-suspend 的 detached backend,保证拿到绑定当前 worker generation +
procStart的精确 CLI/agent 根 pid;Herdr 应从当前 managed agent/pane 的前台进程解析,而不是依赖 worker 子树。 - late pid resolution 不应在固定 3 秒后永久放弃;至少在 idle/guard sweep 时继续重试并可观测地报告 attribution unavailable。
- 增加 Herdr(CLI 在 worker 树外且 attestation 缺失)、Zellij 超过 3 秒才解析、缺失
cliProcStart/PID reuse 的测试。
adopt / restore 复核
当前“不查 ds.session.adoptedFrom”确实尚未形成可触发 bug:startAdoptSession 同时写 runtime/persisted marker;restoreActiveSessions 从 persisted marker 构造 ds.adoptedFrom 后才 forkAdoptWorker;而 forkAdoptWorker 自身没有 runtime marker 会直接 throw,live worker 建立后还有 initConfig.adoptMode 第二层。因此生产路径下 live adopt worker 不会只剩 persisted marker。不过建议与 idle-worker-sweeper 对齐补上 ds.session.adoptedFrom,作为低成本防御纵深,并加回归测试。
验证:
pnpm exec vitest run --project unit test/session-rss-guard.test.ts test/idle-worker-sweeper.test.ts test/session-lifecycle-start.test.ts→ 78/78pnpm exec vitest run test/herdr-backend.e2e.ts→ 9/9pnpm build→ 通过
这个会用在哪一个场景呢? 如果是为了节约内存的话,只要是idle状态的,都可以suspend释放内存(后续无损resume),不需要考虑占用RSS大小。 似乎根据idle的时间去释放更好一些? |
|
确实感觉现在的自动30个(可配置)的自动释放策略基本就足够了,agent做大项目时就是会多使用一些内存,到内存上限自动清理的另一个前提是:需要能精准判断好agent没有放在后台的定时任务(这个目前还没做过特殊判断) |
Summary
maxSessionRssMiBguard for runaway session memory/config, and dashboard bot payloadsVerification
pnpm exec tsc --noEmitpnpm vitest run --project unit test/session-rss-guard.test.ts test/bot-registry.test.ts test/bot-config-store.test.ts test/dashboard-bot-payload.test.ts test/idle-worker-sweeper.test.ts test/api-only-cli-gate.behavior.test.ts test/worker-terminal-read-auth.integration.test.tspnpm buildNote:
pnpm testwas first run before rebuildingdist/, causing the built-CLI gate test to read stale artifacts. Afterpnpm build, the previously failing built-CLI tests passed when rerun.