BLOGE
0.9.9-RC1在线版 · 编制 2026-11-02 · English
第 3 章 —— 用依赖关系思考
承诺: 读完本章后,你会知道如 何把一个 graph 读成依赖结构,如何预测它的执行顺序,以及如何摆脱“按顺序写代码”的思维习惯。
学习目标
- 区分 隐式依赖(由
.output引用推断)与 显式依赖(depends_on)。 - 看到一个 graph 定义时,能够预测哪些节点并行运行、哪些节点必须等待。
- 理解引擎的 completion-driven scheduler 如何把 DAG 变成实际执行计划。
- 识别那些会无意中杀死并行度的多余依赖。
前置条件
源示例
| 文件 | 展示内容 |
|---|---|
order-process.bloge | 真实流程中的扇出、汇合和分支 |
bff-dashboard.bloge | 五路并行扇出与不同韧性策略 |
depends-timeout.bloge | 显式依赖与 timeout |
为什么这很重要
第 2 章里你跑过了一个或两个节点的 graph,那足够你理解基本机制。但真实工作流往往有很多节点和更复杂的依赖关系——这时候,执行顺序已经不是“从上到下看文件”那么简单了。
如果你不理解引擎如何解析依赖关系,通常会遇到这些问题:
- 本来能并行的节点被你错误串行化。
- 引入循环依赖,结果在编译期就被拒绝。
- 做时序排查时总以为系统会“按你眼睛看到的顺序执行”,而实际上引擎从来没有承诺过这一点。
关键转变是:你声明的是“谁依赖谁”,引擎决定的是“何时运行谁”。
心智模型
把 DAG 当成一份承诺
BLOGE graph 是一个 DAG(有向无环图)。每个 node 是顶点,每条 dependency 是有向边。
这样读这张图:
- A 和 B 没有入边 → 它们是 source nodes → 引擎会立刻并行启动它们。
- C 同时依赖 A 和 B → 必须等 两边都完成 才能启动。
- D 只依赖 B → B 一完成它就能启动,即使 A 还在跑。
- E 同时依赖 C 和 D → 它会等待二者都完成。
这就是 completion-driven 的调度模型。某个节点一旦完成,引擎就会检查它的下游:是不是已经满足所有依赖?如果满足,就把该节点投入执行。
隐式依赖与显式依赖
形成边有两种方式:
| 方式 | 语法 | 适用场景 |
|---|---|---|
| 隐式依赖 | 在 input 里引用 someNode.output | 大多数情况下都用它——编译器会自动推断依赖 |
| 显式依赖 | depends_on = [someNode] | 你需要执行顺序,但不需要消费上游数据 |
两者最终形成的是同一种运行时边。大部分时候更常见的是隐式依赖,因为你通常确实需要上游数据。
第一个可运行示例
看看
order-process.bloge
里的依赖结构:
graph orderProcess {
node fetchUser : FetchUserOperator {
input { userId = ctx.userId }
timeout = 3s
}
node fetchProducts : FetchProductsOperator {
input { productIds = ctx.productIds }
timeout = 5s
}
node calcPrice : CalcPriceOperator {
input {
user = fetchUser.output
products = fetchProducts.output
}
}
// ...
}
依赖分析如下:
| 节点 | 依赖谁 | 原因 |
|---|---|---|
fetchUser | (无) | 只读 ctx,是 source node |
fetchProducts | (无) | 只读 ctx,是 source node |
calcPrice | fetchUser |