feat(storage): persist sandbox records in sqlite#329
Conversation
|
PR Title: feat(storage): persist sandbox records in sqlite Commit: 本次PR为沙盒记录引入SQLite持久化层。主要变更:1) 新增 发现的主要问题:
|
|
PR Title: feat(storage): persist sandbox records in sqlite Commit: 本次 PR 完成了 sandbox 记录在 SQLite 中的生命周期管理。核心变更包括:
整体评估:代码结构清晰,并发控制和不变性修复是亮点,测试覆盖较充分。但 |
|
PR Title: feat(storage): persist sandbox records in sqlite Commit: 该 PR 修复了 变更内容:
整体评估: |
4fe4c61 to
d12d2cd
Compare
|
MonkeyScan 检测到 rebase / force-push 等历史改写,正在重新评审当前 PR 的全部有效改动,并自动收敛已消失的历史问题;完成后会更新到本评论中,请稍后刷新查看。 |
|
@monkeyscan 扫描完了吗 |
无法从当前上下文确认扫描是否完成。review_finding 未提供,无法获取扫描状态。 |
@monkeyscan 这个任务执行完成了吗 |
当前上下文无法确认该任务的执行状态,请等待 MonkeyScan 自动更新结果或查看最新评论。 |
|
@monkeyscan 扫描当前pr改动 |
|
PR Title: feat(storage): persist sandbox records in sqlite Commit: 本次 PR 在 SQLite 中新增了 Sandbox 摘要的持久化存储(
整体评估:代码结构清晰,测试覆盖较全面(CRUD、分页、迁移、失败重试)。但发现一处游标分页逻辑缺陷,以及一处创建失败时可能导致孤儿 Sandbox 的问题。 |
d12d2cd to
4825865
Compare
|
@monkeyscan 扫描当前pr改动 |
|
PR Title: feat(storage): persist sandbox records in sqlite Commit: 本次 PR 在现有文件系统存储之外新增了 SQLite 持久化层,用于保存 Sandbox 摘要记录。核心变更包括:
关键设计决策:
整体评价:功能实现完整,测试覆盖良好,但在文件系统锁与数据库 recorder 的协同上存在数据完整性风险,需要关注并发场景下的竞态条件。 |
| return s.saveSandboxPreservingCounts(session) | ||
| // Assign the version timestamp while holding the filesystem lock so it | ||
| // reflects the serialization order used to persist metadata.json. | ||
| session.Summary.UpdatedAt = time.Now().UTC() |
There was a problem hiding this comment.
RemoveSandbox 与 UpdateSandbox/AddEvent 之间存在竞态,可产生已删除沙盒的僵尸数据库记录
UpdateSandbox 和 AddEvent 在释放 per-sandbox 文件系统锁之后才调用 recorder.UpsertSandbox;RemoveSandbox 同样先释放锁再调用 recorder.DeleteSandbox。这意味着两个并发流程可能交错执行:
- UpdateSandbox/AddEvent 完成磁盘写入并释放锁;
- RemoveSandbox 获取锁、删除目录、释放锁、删除数据库记录;
- UpdateSandbox/AddEvent 随后执行 recorder.UpsertSandbox,将已删除沙盒的记录重新写回数据库。
结果是数据库中存在已删除沙盒的“僵尸记录”,与文件系统状态不一致。
Problem code:
Changed code at pkg/storage/sessionstore/store.go:371-380
Recommendation:
将 recorder 操作纳入文件系统锁的保护范围内,或者在执行 recorder upsert 前检查沙盒目录是否仍然存在;对于删除操作,也可考虑在锁内设置“删除中”标记以阻止并发更新。
| } | ||
| sandboxToRecord = session | ||
| return nil | ||
| }(); err != nil { |
There was a problem hiding this comment.
AddEvent 在 recorder 失败后重试可能导致事件重复追加
AddEvent 在已持有文件系统锁的闭包内先调用 s.appendEvent 将事件追加到 JSONL 文件,并更新 event count 和 metadata,随后释放锁。闭包外部再调用 recorder.UpsertSandbox。如果 recorder 失败,AddEvent 会返回错误。
调用方若基于该错误重试,会再次进入闭包、再次 appendEvent,导致同一条事件被重复追加到 JSONL,且 event count 也会重复累加。这与 CreateSandbox 对 recorder 失败仅记录日志的行为不一致。
Problem code:
Changed code at pkg/storage/sessionstore/store.go:562-566
Recommendation:
使 AddEvent 对 recorder 失败采用与 CreateSandbox 一致的降级策略(记录警告后返回成功),或在 appendEvent 层实现基于事件 ID 的幂等去重,避免重试导致重复事件。
Summary
sandboxestable and indexes for persisted sandbox summary records.metadata.jsonas the current source of truth;ListSandboxesis not switched to SQLite in this change.Testing
go test ./pkg/storage/configstore ./pkg/storage/sessionstore ./pkg/agentcompose/appgo test -race ./pkg/storage/configstore ./pkg/storage/sessionstoretask linttask buildtask build:agent-composetask test127.0.0.1:17410with an isolated data root.agents/docker-scheduler-exec-logs.sandboxesrows matchedmetadata.jsonfor ID, driver, status, image, runtime reference, cell count, event count, and timestamps.Checklist