Skip to main content

lellm_graph/
checkpoint.rs

1//! Checkpoint — 执行恢复的唯一数据源。
2//!
3//! Checkpoint 的唯一职责:**恢复(Restore)**。
4//!
5//! - 不含 `parent_trace_id` — 与 Trace 通过存储层组织关联,非结构体关联
6//! - 不含 `effect_log` — Effect 审计走 `ExecutionTrace`
7//! - 不含 `snapshot` — 增量快照是存储层优化,不应泄漏到 Checkpoint 结构
8//!
9//! 给我一个 Checkpoint 文件,我就能恢复。不需要任何其他东西。
10
11use serde::{Deserialize, Serialize};
12
13use crate::state::State;
14use crate::workflow_state::WorkflowState;
15
16// ─── CheckpointId ──────────────────────────────────────────────
17
18/// Checkpoint 唯一标识。
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub struct CheckpointId(pub uuid::Uuid);
21
22impl std::fmt::Display for CheckpointId {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        write!(f, "{}", self.0)
25    }
26}
27
28// ─── NodeId ────────────────────────────────────────────────────
29
30/// 节点标识。
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32pub struct NodeId(pub String);
33
34impl std::fmt::Display for NodeId {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        write!(f, "{}", self.0)
37    }
38}
39
40// ─── Checkpoint ────────────────────────────────────────────────
41
42/// 执行检查点 — 物化快照 + 执行游标。
43///
44/// Checkpoint 的唯一职责:恢复(Restore)。
45/// 给我一个 Checkpoint,我就能从 `current_node` 开始,用 `state` 继续执行。
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct Checkpoint<S = State> {
48    /// 唯一标识
49    pub checkpoint_id: CheckpointId,
50    /// 下一个要执行的节点
51    pub current_node: NodeId,
52    /// 物化状态快照
53    pub state: S,
54    /// 创建时间
55    pub created_at: std::time::SystemTime,
56}
57
58impl<S: WorkflowState> Checkpoint<S> {
59    pub fn new(current_node: impl Into<String>, state: S) -> Self {
60        Self {
61            checkpoint_id: CheckpointId(uuid::Uuid::new_v4()),
62            current_node: NodeId(current_node.into()),
63            state,
64            created_at: std::time::SystemTime::now(),
65        }
66    }
67}
68
69// ─── CheckpointStoreError ──────────────────────────────────────
70
71/// Checkpoint 存储操作错误。
72#[derive(Debug, thiserror::Error)]
73pub enum CheckpointStoreError {
74    #[error("storage error: {0}")]
75    Storage(String),
76    #[error("checkpoint not found: {0}")]
77    NotFound(CheckpointId),
78    #[error("corrupted checkpoint: {0}")]
79    Corrupted(String),
80}
81
82// ─── CheckpointStore trait ─────────────────────────────────────
83
84/// Checkpoint 存储后端 SPI。
85///
86/// 与类型解耦 — 存储层序列化/反序列化 `S`。
87#[async_trait::async_trait]
88pub trait CheckpointStore: Send + Sync {
89    /// 保存 Checkpoint 并关联 trace_id。
90    async fn save_with_trace(
91        &self,
92        trace_id: &TraceId,
93        checkpoint: &Checkpoint,
94    ) -> Result<(), CheckpointStoreError>;
95    async fn load(&self, id: &CheckpointId) -> Result<Option<Checkpoint>, CheckpointStoreError>;
96    async fn load_latest(
97        &self,
98        trace_id: &TraceId,
99    ) -> Result<Option<Checkpoint>, CheckpointStoreError>;
100    async fn list(&self, trace_id: &TraceId) -> Result<Vec<CheckpointId>, CheckpointStoreError>;
101    async fn delete(&self, id: &CheckpointId) -> Result<bool, CheckpointStoreError>;
102    async fn prune(&self, trace_id: &TraceId, keep: usize) -> Result<usize, CheckpointStoreError>;
103}
104
105// ─── CheckpointPolicy ──────────────────────────────────────────
106
107/// Checkpoint 策略 — 控制何时保存。
108#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
109pub enum CheckpointPolicy {
110    /// 每次节点执行后保存
111    #[default]
112    EveryNode,
113    /// 仅在 Barrier 决策后保存
114    BarrierOnly,
115    /// 手动控制 — 调用方显式触发
116    Manual,
117}
118
119// ─── TraceId Re-export ─────────────────────────────────────────
120
121/// 从 ids 模块重导出 TraceId,供 CheckpointStore trait 使用。
122///
123/// 注意:Checkpoint 结构体**不包含** trace_id。
124/// 关联关系由存储层组织(如同一目录下的文件)。
125pub use crate::ids::TraceId;