Files
storage-labos/flashops/docs/decisions/0002-event-sourcing.md
T
yuanshuai c91a64fddb
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run
chore(repo): initialize team collaboration repository
2026-07-27 20:40:12 +08:00

45 lines
2.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0002:以事件溯源作为 Run 的唯一真相
- 日期:2026-07-27
- 状态:已接受
## 背景
产品要交付的三件事——**统一时间线**、**审计**、**自动复现**——都需要回答同一个问题:
"当时到底按什么顺序发生了什么"。
同时,观测是**双通道**的:Agent 报一套,带外控制器报一套,两者时钟不同步,
主机断电时 Agent 那一路会直接消失。
## 决定
`run_events` 是 append-only 的唯一真相。`runs` / `run_steps` / `recovery_actions`
是可以从事件重放重建的**读模型**。
序号 `seq` 由控制平面单点分配(不是时间戳排序),Agent 事件与带外事件进同一条序列。
仓储层**不提供** `update_run_state()` 类 API。改状态的唯一入口是
`events/recorder.py::record()`,它写事件并同步更新投影。
## 理由
- 主机断电时,Agent 的最后几条日志可能永远到不了。带外控制器的观测
(掉电时刻、画面指纹)是那段时间唯一的证据。两路事件必须在同一条时间线上
才能交叉校验——"Agent 最后一条日志 seq=812,带外报掉电 seq=813"这种判断
只有单点序号能给。
- 审计要求记录"操作者、审批者、命令模板版本、输入参数、结果、撤销动作"
(方案 §6.6)。这些天然是事件,硬塞进当前状态表会做成一堆冗余字段。
- 自动复现(§8.4)需要"失败前后的最小步骤区间"。有完整事件流才能裁剪。
## 代价
- 写路径变长,每次状态变化多一次插入。
- `run_events` 会很大:100 循环 × 每轮 ~30 事件 = 3000 条/Run。
缓解:事件按 run_id 分区友好,日志正文不进事件表(只存对象存储 URI)。
- 开发者容易忍不住直接 UPDATE。缓解:仓储层不给这个 APIcode review 卡这一条。
## 什么时候推翻
不推翻。真要优化,是加快照(每 N 个事件存一次状态快照加速重放),
不是放弃事件溯源。