Checkpoint 概念¶
本页讲清断点续执的执行模型:什么时候挂起、上下文怎么存、怎么恢复。
执行模型¶
Distributed 模式下,每次 run_distributed 只推进一个节点。遇到 EventNode 时订阅事件并挂起,调用方拿到挂起快照后持久化,等外部事件到达再恢复。
sequenceDiagram
participant Caller as 调用方
participant FE as FlowExecution
participant Bus as EventBus
participant Store as ExecutionStorage
Caller->>FE: run_distributed(flow, params)
FE->>FE: clean + on_flow_start + setup_flow
FE->>FE: 执行节点... 到达 EventNode
FE->>Bus: register_subscription(...)
FE-->>Caller: {is_suspend: true, context}
Caller->>Store: save(execution_id, context)
Note over Caller: ...时间流逝...
Caller->>Store: load(execution_id)
Caller->>FE: run_distributed(flow, None, saved_context, resume_type="event", resume_data)
FE->>FE: on_flow_resume + on_node_resume
FE->>FE: node.on_event(execution, resume_data)
FE-->>Caller: 恢复挂起节点本身(is_end=false)
Caller->>FE: 继续推进:run_distributed(resume_type="continue")×N
FE-->>Caller: {is_end: true, result}
挂起¶
DistributedStrategy._execute_current_node 检测到当前节点是 EventNode 时:
_subscribe_event:从上下文取 event bus,调用register_subscription(event_type, filter_condition, correlation_id=execution_id, flow_id, node_id),把订阅 id 回写到节点状态on_node_suspend(flow, node)/on_flow_suspend(flow)触发回调- 返回
_create_lazy_output(..., is_suspend=True, context=...)
调用方拿到 context(含 $LAST_NODE / $NODE[event_node_id] 状态)后,自行存入 ExecutionStorage。
恢复¶
恢复时调用 run_distributed(flow, None, saved_context=ctx, resume_type=..., resume_data=...)。resume_type 决定如何唤醒挂起的事件节点:
| resume_type | 行为 | 调用 |
|---|---|---|
event |
事件到达 | node.on_event(execution, resume_data) |
timeout |
等待超时 | node.on_timeout(execution) |
cancel |
取消等待 | node.on_cancel(execution) |
continue |
不唤醒,从 LAST_NODE 之后继续下一节点 |
— |
注意 event / timeout / cancel 只恢复挂起节点本身(本次调用的返回即该节点状态);后续节点要用 resume_type="continue" 逐次推进,直到 is_end。continue 在挂起节点仍为 pending 时会被拒绝(防止静默跳过事件)。
恢复前会校验:挂起节点确实是 EventNode、其状态为 pending、resume_type 在允许集合内,否则抛 FlowExecutionException。
复用 execution 实例¶
贯穿步骤保留回调
execution = FlowExecution(callback_handlers=[MyCallback()])
step = execution.run_distributed(flow, params) # 挂起
save(step["execution_id"], step["context"])
# ...
step = execution.run_distributed(flow, None, saved_context=load(...),
resume_type="event", resume_data=data) # 恢复
复用同一个 FlowExecution 实例,回调与上下文贯穿所有步骤。
若用类方法 FlowExecution.run(..., mode='distributed'),每次会新建实例,回调不保留。
执行流程图¶
上下文序列化¶
ExecutionContext.to_dict() 返回 CheckpointState.to_checkpoint_dict()(与旧 dict(self._context) 格式逐键兼容,可 JSON 序列化存入 ExecutionStorage)。恢复时由 DistributedStrategy 把 saved_context(plain dict)赋给 context.context,setter 经 CheckpointState.from_checkpoint_dict 解析回 typed model。
注意 cancel_event(threading.Event)不可 pickle,子进程会拿到全新未触发事件——跨进程取消不支持(见 状态管理)。
EventNode 状态¶
EventNode 维护状态机(EventNodeStatus):
pending (等待) --on_event--> completed
\---on_timeout-> timeout
\--on_cancel--> cancelled
\-on_error---> error
on_event 把 event_data 写进状态并置 completed,节点输出可在后续被 $NODE.event_node_id.event_data 引用。
下一步¶
- 事件系统 —— EventBus 如何连接挂起流程与外部触发
- FlowWorker —— 编排器封装;先读 可靠性边界
- 执行模式 - Distributed