Skip to main content

BLOGE 0.9.8-RC1 在线版 · 事实校验 2026-09-15 · English

第三阶段回顾 —— 组合与时间(第 10–13 章)

你现在可以用可复用的部件组合大型工作流、遍历集合、挂起等待外部事件,并在进程重启后恢复执行。


你学到了什么

第 10 章 —— 用子图复用 引入了 subgraph("name") 语法。你学会了用 DslCompiler.registerSubGraph() 注册预构建的 Graph、将其嵌入父 graph,并控制作用域隔离(isolated vs. parent)。你还看到了 dynamicSubGraph(运行时动态生成 DSL)在什么场景下更合适。

第 11 章 —— 批处理与迭代 展示了两个循环原语:foreach(遍历集合,每个元素执行一次子 graph 并收集结果)和 loop(带 max_iterationsdelayuntil 的可控重复)。你了解了批处理结果如何收集,以及 loopIteration 如何提供从零开始的计数器。

第 12 章——等待世界的回应 增加了挂起能力。通过 await,graph 暂停执行且不持续占用 worker thread,只有外部信号到达或超时后才恢复。你练习了按 key 关联事件,以及根据信号是否到达来分支执行。

第 13 章——持久执行 增加了重启恢复所需的 store 与 identity。满足条件的 worker 可以接受 checkpoint、跳过已完成节点并继续剩余前沿;尚未提交 checkpoint 的外部副作用仍需要幂等或对账。


你现在应该能做到

  • 将可复用的流程提取为命名子图,并嵌入多个父 graph。
  • foreach 处理集合、用 loop 实现轮询循环,并为每种场景选择正确的原语。
  • await 挂起 graph、关联外部事件,并优雅地处理超时。
  • 将持久化 store 接入 GraphEngine,并演示 挂起 → 崩溃 → 冷恢复 → 继续执行 的完整流程。
  • 解释 checkpoint、执行标识和 graph 注册表之间的关系。

这个阶段的常见错误

错误为什么会犯如何纠正
在应该用 isolated 作用域时用了 parent"子图只需要父 graph 的一个值"默认使用 isolated 作用域,通过子图输入绑定显式传递所需值。parent 作用域会泄漏整个 context。
无限循环(没有 until 也没有 max_iterations忘记 loop 默认是无界的即使 until 通常会先退出,也始终设置 max_iterations 作为安全网。
await 当成 Thread.sleep()混淆了挂起和阻塞的概念await 等待时不持续阻塞 worker thread;持久化 wait、timer 与 correlation 状态仍会消耗系统资源。
开发时跳过持久化 store“以后再加持久化”用内存 store 实现练习 API 与恢复路径,同时记住它们会随进程退出而丢失状态。
不测试恢复路径只测试没有任何崩溃的快乐路径至少写一个测试:执行到一半,创建新引擎,从 checkpoint 恢复。

新增核心词汇

术语含义
子图(Subgraph)一个按名称注册的预构建 Graph,作为单个节点嵌入父 graph。
foreach遍历集合,为每个元素执行一次循环体并收集结果。
loop最多重复执行 max_iterations 次,可选 delayuntil 退出条件。
loopIteration每个循环体内可用的从零开始的内置计数器。
await挂起 graph 并释放线程,直到外部信号到达或超时。
Checkpoint每个节点完成后对 node 输出和执行状态的持久快照。
冷恢复(Cold recovery)在另一个引擎实例上,通过从持久化存储加载 checkpoint 来恢复 graph 执行。

试一试:选择正确的时间模型

一个订单流程要处理 200 个商品、最多轮询库存五次,还可能等待客户确认两天。请分别选择 foreachloopawait,并标出哪些状态必须跨进程重启保存。再解释为什么用 sleep 循环替代 await 会占住错误的资源,并隐藏外部 signal 边界。


下一步

第四阶段回顾 将重心从“持久的一次性执行”转向“更长生命周期的编排模式”:session、状态机,以及嵌套生命周期所有权。从第 14 章 —— 多轮 Session开始。