Skip to content

Commit 13046ea

Browse files
committed
docs: add live session runtime optimization plan
1 parent 3529447 commit 13046ea

3 files changed

Lines changed: 247 additions & 0 deletions

File tree

docs-linhay/memory/2026-05-27.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# 2026-05-27
2+
3+
## Codex live-session runtime optimization
4+
5+
- 新建 space:`docs-linhay/spaces/20260527-codex-live-session-runtime-optimization/`
6+
- 背景:排查 `cli-proxy-api` RSS 与 `sidecar.log` 增长时,确认 `/v0/management/gettokens/live-sessions` 当前返回 realtime 全量快照,列表轮询会反复序列化 session/request/timeline;缺失 `projectName` 时还可能触发 `.codex` JSONL 扫描。
7+
- 决策:按“列表轻量化、详情分页化、projectName 补全移出 snapshot 热路径、前端轮询降频/隐藏暂停、access log 降噪、realtime 内存与 disk history 分离”的方向推进。
8+
- 计划入口:`docs-linhay/spaces/20260527-codex-live-session-runtime-optimization/plans/runtime-optimization-plan-v01.md`
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Codex Live Session Runtime Optimization
2+
3+
## 背景
4+
5+
2026-05-27 排查 `cli-proxy-api` RSS 偏高与 `sidecar.log` 快速增长时,确认 `GET /v0/management/gettokens/live-sessions` 被高频轮询。该接口当前返回 live tracker 的完整实时快照:`sessions[]` 下包含 `requests[]`,每个 request 又包含 `timeline[]`。同时,缺失 `projectName` 的 session 会触发 `.codex/sessions``.codex/archived_sessions` JSONL 扫描缓存刷新,TTL 只有 10 秒。
6+
7+
这不是“未写数据库”的问题。`usage-observed-v1.sqlite``usage-attribution-v1.sqlite` 仍在更新;真正的问题是 realtime observability 的列表接口、轮询节奏、项目名补全、日志记录和内存留存边界混在一起,导致 CPU、RSS、磁盘日志和接口响应体一起放大。
8+
9+
## 目标
10+
11+
1. 将 live-session 列表轮询降为低成本、低日志、低响应体的 runtime row feed。
12+
2. 将 request/timeline 详情改为按 session/detail 场景懒加载,并与已存在的历史 SQLite 分页语义对齐。
13+
3. 避免 snapshot 热路径触发 `.codex` 全量 JSONL 扫描。
14+
4. 保持 live-session UI 只读观测能力,不引入取消、重放、强制恢复等操作型能力。
15+
5. 在不丢失历史诊断价值的前提下,压缩 realtime 内存留存。
16+
17+
## 范围
18+
19+
1. CLIProxyAPI fork:live-session management endpoints、runtime tracker、project name enrichment、gin access log 降噪。
20+
2. GetTokens Wails bridge:必要时补充 root App DTO/method 映射与生成绑定。
21+
3. Frontend live sessions workspace:轮询策略、列表/详情数据源拆分、页面隐藏暂停、浏览器 preview fallback。
22+
4. 测试:tracker 纯模型/endpoint tests、Wails binding tests、frontend model/source tests、至少一轮本地 runtime smoke。
23+
5. 文档:本 space、必要的 dev 技术说明、memory 写回。
24+
25+
## 非目标
26+
27+
1. 不展示原始 request/response payload、credentials、bearer token、cookie 或未脱敏错误体。
28+
2. 不新增 request cancel、replay、强制 WebSocket 恢复。
29+
3. 不删除 live-session 历史库;realtime prune 与 disk history cleanup 必须分离。
30+
4. 不把浏览器 preview 当成 Wails/sidecar runtime 的完整替代验收。
31+
32+
## 验收标准
33+
34+
### 场景 1:列表轮询轻量化
35+
36+
Given Codex live sessions 页面打开并处于前台,When 前端轮询 live-session 列表,Then 列表接口只返回 summary 与 session row 字段,不包含 `requests[]` 和 request `timeline[]`
37+
38+
### 场景 2:详情懒加载
39+
40+
Given 用户点击某个 live session 行,When 详情面板打开,Then 才按 `session_id` 拉取 request/timeline 详情,并支持 `limit / offset / window` 分页或等价约束。
41+
42+
### 场景 3:页面不可见暂停
43+
44+
Given live sessions workspace 不可见、窗口隐藏或用户切到其他 workspace,When 没有显式详情刷新需求,Then 前端停止轮询或降到低频,不继续刷 `sidecar.log`
45+
46+
### 场景 4:项目名补全不阻塞 snapshot
47+
48+
Given 某些 session 缺失 `projectName`,When 调用列表 snapshot,Then snapshot 不同步全盘扫描 `.codex` JSONL;项目名通过请求时携带、精准查找或后台缓存刷新补齐。
49+
50+
### 场景 5:实时内存可控且历史不丢
51+
52+
Given 有大量 Codex requests 通过 sidecar,When 请求完成并超过 realtime 留存窗口,Then 内存 tracker 只保留必要摘要或被 prune;历史详情仍可从 disk-backed history endpoint 分页查询。
53+
54+
### 场景 6:日志降噪
55+
56+
Given live sessions 列表接口稳定 2xx 且响应未变,When 前端持续观测,Then sidecar access log 不再为每次成功轮询写完整 info 行,或至少对该路径采样/降级/慢请求记录。
57+
58+
## 设计稿入口
59+
60+
- 本期设计稿:`(未产出)`
61+
- 约束:单期只保留一个 HTML 文件;若存在多稿对比,也必须收敛在同一个 HTML 文件内。
62+
63+
## Worktree 映射
64+
65+
- branch:`feat/20260527-codex-live-session-runtime-optimization`
66+
- worktree:`../GetTokens-worktrees/20260527-codex-live-session-runtime-optimization/`
67+
68+
## 相关链接
69+
70+
- 技术计划:`plans/runtime-optimization-plan-v01.md`
71+
- 领域规则:`.agents/skills/gettokens-domain-engineering/SKILL.md``Codex Live Sessions`
72+
- 已有关联 space:
73+
- `docs-linhay/spaces/20260521-codex-live-session-detail/README.md`
74+
- `docs-linhay/spaces/20260523-codex-live-session-current-account/README.md`
75+
- `docs-linhay/spaces/20260525-codex-live-session-request-info/README.md`
76+
77+
## 当前状态
78+
- 状态:draft
79+
- 最近更新:2026-05-27
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Runtime Optimization Plan v01
2+
3+
## 诊断结论
4+
5+
当前风险不是单点内存泄漏,而是观测面设计过重:
6+
7+
1. `/v0/management/gettokens/live-sessions` 返回完整 realtime snapshot,列表轮询会反复序列化 `sessions -> requests -> timeline`
8+
2. 前端 live workspace 高频轮询导致 access log 快速增长。
9+
3. `projectName` 补全在 snapshot 热路径上,缓存 TTL 只有 10 秒,缺失名称时可能反复扫 `.codex` JSONL。
10+
4. realtime tracker 和 disk history 职责已有边界,但列表接口仍把详情级数据混入默认响应。
11+
5. Gin access log 对高频 2xx management polling 没有降噪策略。
12+
13+
## 优化面清单
14+
15+
### 1. API Shape
16+
17+
- 新增或调整列表接口为轻量 row feed:
18+
- `summary`
19+
- `sessions[]` row fields:`sessionID / projectName / status / model / authID / authLabel / provider / downstreamTransport / upstreamTransport / startedAt / lastEventAt / durationMs / requestCount / activeRequestID / lastRequestID / fallback flags`
20+
- 不包含 `requests[]`
21+
- 不包含 request `timeline[]`
22+
- 保留详情接口:
23+
- 优先复用 `/gettokens/live-sessions/history?session_id=...&limit=...&offset=...`
24+
- 如前端需要 active request 的最新投影,可新增 `/gettokens/live-sessions/:session_id/detail`
25+
- 支持轻量变更检测:
26+
- `etag``snapshotVersion`
27+
- `since` / `last_event_at` 查询
28+
- 无变化返回极小 payload 或 `304`
29+
30+
### 2. Frontend Polling
31+
32+
- workspace 可见且有 active session:2s 轮询。
33+
- workspace 可见但无 active session:5-10s 轮询。
34+
- workspace 不可见、窗口 hidden、切到非 live workspace:暂停或 30s 低频。
35+
- 详情面板独立刷新:
36+
- 列表刷新不带详情。
37+
- 详情打开时按 `session_id` 拉 requests/timeline。
38+
- 切换详情时取消上一个 pending request。
39+
- 浏览器 preview 保持 mock/live/cache 来源标识,不依赖真实 sidecar。
40+
41+
### 3. Project Name Enrichment
42+
43+
- 首选:记录 request/session 时从 Codex metadata/header/context 直接注入 `projectName`
44+
- 次选:按 session id 精准查候选 JSONL,而不是全量 walk。
45+
- 后台缓存:
46+
- snapshot 不同步触发全盘扫描。
47+
- 全局 lookup TTL 从 10 秒提高到 5-10 分钟。
48+
- 缓存刷新放 goroutine,并有 singleflight 防止并发重复扫。
49+
- fallback:项目名缺失时前端显示 `未知项目`,不要为了补全阻塞列表。
50+
51+
### 4. Realtime Memory
52+
53+
- tracker 内拆分 row 与 detail:
54+
- row 常驻:小字段、最新状态、最近时间。
55+
- detail 只保留 active request + 最近 N 条摘要。
56+
- completed request 瘦身:
57+
- 完成后将 timeline 压成摘要,完整历史写入 SQLite。
58+
- request detail 通过 history endpoint 查询。
59+
- prune 策略:
60+
- 保留 30m realtime window。
61+
- session cap 与 request cap 继续生效,但完成态可更激进。
62+
- prune 不删除 disk history。
63+
64+
### 5. Logging
65+
66+
-`/v0/management/gettokens/live-sessions` 成功 2xx access log 降噪:
67+
- 默认 debug 级别
68+
- 只记录慢请求,例如 `>500ms`
69+
- 或按 N 次采样
70+
- 仍记录 4xx/5xx
71+
-`rate-limit-status / strategies` 等管理轮询同样考虑慢请求/异常优先。
72+
- 保留 request id、状态码、耗时的诊断能力,但避免每 2 秒刷一行 info。
73+
74+
### 6. Observability Diagnostics
75+
76+
- 增加轻量 runtime metrics endpoint 或 debug panel 字段:
77+
- realtime session count
78+
- active request count
79+
- retained request count
80+
- estimated snapshot bytes
81+
- project lookup cache age
82+
- last project lookup duration
83+
- history DB write error count
84+
- 这些指标只用于诊断,不显示敏感 payload。
85+
86+
### 7. Disk History
87+
88+
- 确认 `live_session_requests` history store 的分页查询覆盖详情页需要。
89+
- 历史库写入失败时只暴露脱敏错误与计数,不在 hot path 重试放大。
90+
- 若需要清理历史,单独设计 disk cleanup API,不能复用 realtime `DELETE /live-sessions`
91+
92+
## 分阶段计划
93+
94+
### Phase 0:基线与失败测试
95+
96+
1. 固化当前问题的 BDD 场景。
97+
2. 增加 endpoint 测试:列表 snapshot 不应包含 `requests`
98+
3. 增加 tracker 测试:snapshot 不触发项目名全盘扫描。
99+
4. 增加 frontend source 测试:隐藏或非 workspace 时停止轮询。
100+
5. 记录当前 baseline:
101+
- snapshot payload bytes
102+
- 轮询频率
103+
- `sidecar.log` 每分钟增长量
104+
- RSS 与 retained request count
105+
106+
### Phase 1:列表接口瘦身
107+
108+
1. 新增 `LiveSessionRow` DTO。
109+
2.`/gettokens/live-sessions` 改为 row feed。
110+
3. 保持旧详情字段从 history/detail endpoint 获取。
111+
4. 更新 Wails/root DTO 与 generated bindings。
112+
5. 前端列表消费 row feed,详情按需拉取。
113+
114+
### Phase 2:轮询与日志降噪
115+
116+
1. 前端按 workspace visibility 和 active session 调整轮询。
117+
2. 页面 hidden 时暂停。
118+
3. Sidecar 对 live-session 2xx access log 采样或慢请求记录。
119+
4. 添加测试覆盖 polling policy。
120+
121+
### Phase 3:ProjectName 热路径移除
122+
123+
1. 从请求 metadata/header/context 优先写入 projectName。
124+
2. 将全盘 `.codex` lookup 移出 snapshot 同步路径。
125+
3. 增加缓存 TTL 与 singleflight。
126+
4. 添加测试:snapshot 在缺失 projectName 时不阻塞、不触发全盘 scan。
127+
128+
### Phase 4:Realtime 内存留存
129+
130+
1. completed request 写入 disk history 后在内存瘦身。
131+
2. tracker 中保留 active request + 最近摘要。
132+
3. history endpoint 补齐详情分页。
133+
4. 添加测试:大量 completed request 不使 row snapshot 膨胀。
134+
135+
### Phase 5:验收与写回
136+
137+
1. `go test` 覆盖 CLIProxyAPI fork 相关包。
138+
2. GetTokens root/Wails binding 测试。
139+
3. Frontend focused tests、typecheck、build。
140+
4. 本地 sidecar smoke:
141+
- 打开 live-session 页面
142+
- 观察 snapshot payload size
143+
- 观察 `sidecar.log` 增长速度
144+
- 验证详情仍可打开 request timeline
145+
5. 更新本 space、必要 dev 文档、memory,并执行 `qmd update && qmd embed`
146+
147+
## 风险与取舍
148+
149+
1. 兼容性:如果前端旧逻辑依赖列表中直接存在 `requests[]`,需要一次性迁移到 detail source。
150+
2. 诊断完整性:列表瘦身不能丢失历史;详情必须能从 disk history 找回。
151+
3. 项目名准确性:异步补全可能短时间显示 `未知项目`,但这是可接受的性能取舍。
152+
4. 日志降噪:不能静默吞掉 4xx/5xx 和慢请求,否则排障会变难。
153+
5. 内存瘦身:active streaming request 仍需要实时 timing 投影,不能像 completed request 一样过早压缩。
154+
155+
## 推荐优先级
156+
157+
1. P0:列表接口瘦身 + 前端轮询暂停 + access log 降噪。
158+
2. P1:projectName 补全移出 snapshot 热路径。
159+
3. P2:completed request 内存瘦身 + history detail 分页完善。
160+
4. P3:etag/since 与 runtime metrics endpoint。

0 commit comments

Comments
 (0)