graph - 高级节点模式(网关)
2026年1月5日 上午10:53:09
1、什么是网关(Gateway)?
在 Solon-Flow 的世界观里,节点分为活动节点(Activity)和网关节点(Gateway)。
- 执行节点:负责“干活”(执行具体的 Task)。
- 网关节点:可以“干活”,还可以负责“调度”(决定流向、等待分支、循环数据)。
2、四大常用网关再对比一下
(在 Solon Flow 开发,节点类型处有介绍)通过下表,你可以快速决定在业务中使用哪种网关:
| 网关类型 | 逻辑特征 | 现实类比 | 适用场景举例 |
|---|---|---|---|
| EXCLUSIVE (排他) | 多个分支只走其一 | 单选题 | 根据金额选择审批人。 |
| INCLUSIVE (包容) | 满足条件的全部都走 | 多选题 | 满足“金额大”且“有风险”时,同时触发两个预警。 |
| PARALLEL (并行) | 全部都走 | 全选题 | 同时调用三方支付、短信、库存接口。 |
| LOOP (循环) | 按集合数据循环往复 | 传送带 | 批量给一组用户发通知。 |
3、高级实战:并行与聚合 (Parallel & Join)
这是提升系统吞吐量的“杀手锏”。利用并行网关,你可以让原本串行的任务在多个线程中同时运行。
场景:多源风控校验 我们需要同时调用三个风控引擎,只有全部返回后,流程才能继续。
spec.addParallel("fork_node"); // 开启并发点
spec.addActivity("ali_risk").task("@aliService").linkAdd("join_node");
spec.addActivity("tencent_risk").task("@tenService").linkAdd("join_node");
spec.addActivity("local_risk").task("@localService").linkAdd("join_node");
// 这是一个聚合点,引擎会自动等待上方三个分支全部到达
spec.addParallel("join_node").linkAdd("final_decision");
// 编排连接关系
spec.getNode("fork_node")
.linkAdd("ali_risk")
.linkAdd("tencent_risk")
.linkAdd("local_risk");
底层揭秘:FlowEngine 在执行并行网关时,会尝试获取驱动中的线程池。如果有线程池(通过驱动器配置),它会通过 CountDownLatch 阻塞主链条,直到所有子分支线程执行完毕。
4. 智能编排:循环网关 (Loop)
循环网关通过元数据(Meta)驱动,能够优雅地处理列表遍历。
关键元数据配置:
$for:当前循环项存入 Context 的变量名。$in:数据源。可以是 List 变量名,也可以是步进表达式(如 1:10:1)。
示例:批量任务处理
spec.addLoop("loop_start")
.metaPut("$for", "item") // 每次循环的对象叫 item
.metaPut("$in", "dataList") // 从上下文获取 dataList
.linkAdd("process_task");
spec.addActivity("process_task").task("@myProcessor").linkAdd("loop_end");
// 结束点,如果不满足退出条件,引擎会根据 loop_stack 自动回流
spec.addLoop("loop_end");
5、避坑指南
为了保证流程的高可用,在使用高级网关时请务必注意:
- 线程池依赖:并行网关(Parallel)若想实现真正的并发,必须在 FlowDriver 中注入 ExecutorService,否则它会退化为单线程顺序执行。
- 变量可见性:由于并行分支在不同线程运行,通过 FlowContext.put() 写入变量时要注意并发冲突,尽量在并行结束后再进行结果汇总。
- 死循环保护:在动态拼装 Loop 逻辑时,建议配合 FlowInvocation 的执行深度限制(depth),防止因为配置错误导致 CPU 飙升。
结语
掌握了高级网关,你便拥有了处理复杂分布式业务的“指挥棒”。Solon-Flow 的强大之处在于,它用最简单的 addNode 语法,封装了复杂的线程同步与状态管理逻辑。