轻流:用 YAML 风格文本表达串行/并行流程

轻流:用 YAML 风格文本表达串行/并行流程

为什么需要“轻流”?

在日常开发中,我们经常需要描述一段执行顺序明确、结构简单的流程:

“先校验权限,然后并行下载文件和加载配置,接着处理数据,最后同时写入结果并上报指标。”

这类逻辑通常出现在自动化脚本、服务编排、CI/CD 步骤或内部工具中。但若为此引入 BPMN 图形建模,成本过高;若仅用代码硬编码,又难以配置化与可视化。

“轻流”应运而生:它用 YAML 风格的纯文本,仅通过 series(串行)和 parallel(并行)两个关键字,清晰表达上述流程——无需图形、无需复杂语法,一行配置即是一张流程图。

直观效果示例(带注释)

series:                       # 整个流程是串行执行(从上到下)
   - check_permission          # 第1步:校验权限(单任务)
   - parallel:                 # 第2步:并行执行以下两个子任务(同时开始)
       - download_source       #   ↳ 子任务A:下载源文件
       - load_config           #   ↳ 子任务B:加载配置
   - transform_data            # 第3步:转换数据(等并行任务全部完成后执行)
   - parallel:                 # 第4步:再次并行执行输出与监控
       - write_output          #   ↳ 子任务A:写入输出文件
       - emit_metrics          #   ↳ 子任务B:上报指标

✅ 一眼看懂:

  • 缩进层级 = 执行层级
  • series 下的任务按顺序执行
  • parallel 下的任务并发执行
  • 并行块整体视为“一个步骤”,完成后才进入下一步

1. 文本流程语法(YAML 风格 / 格式化的 json )

使用 seriesparallel 关键字 + 子节点数组定义流程结构。

  • 叶子节点:字符串(任务标识)
    • 具体放什么内容,可视情况需要来定
    • 比如:前期交流表达流程时,就可以是很宽松的文本
    • 比如:想要表达更格式化的信息,可以 $id:$name:$desc
  • 容器节点:含 seriesparallel 字段的对象,值为子节点列表
  • 支持任意层级嵌套

示例

简单串行

series:
   - validate    # 第一步
   - process     # 第二步(validate 完成后执行)
   - save        # 第三步(process 完成后执行)

并行执行

parallel:
   - send_email    # 三个任务同时开始
   - update_cache
   - log_event

嵌套混合

series:
   - auth                    # 先认证
   - parallel:               # 再并行获取用户和角色信息
       - fetch_user
       - fetch_role
   - render                  # 等两者都完成后渲染页面

2. Java 模型定义(其它类似)

所有节点统一实现空标记接口 TxtNode,明确其“流程节点”职责。

// 标记接口:所有流程节点必须实现
 public interface TxtNode {}

叶子节点(原子任务)

public record TxtTask(String name) implements TxtNode {}
 // 可扩展业务特定叶子节点,如:
 // public record TxtApiCall(String endpoint) implements TxtNode {}

容器节点(组合结构)

public record TxtSeries(List<TxtNode> steps) implements TxtNode {}
 ​
 public record TxtParallel(List<TxtNode> branches) implements TxtNode {}

所有流程均由 TxtNode 构成,支持统一递归处理。

3. 模型 ↔ 文本转换

3.1 模型 → YAML(序列化)

public class FlowYamlWriter {
     public static String toYaml(TxtNode node) {
         if (node instanceof TxtTask task) {
             return task.name();
         } else if (node instanceof TxtSeries series) {
             return "series:\n" + indentList(series.steps());
         } else if (node instanceof TxtParallel parallel) {
             return "parallel:\n" + indentList(parallel.branches());
         }
         throw new IllegalArgumentException("Unsupported node: " + node);
     }
 ​
     private static String indentList(List<TxtNode> nodes) {
         return nodes.stream()
             .map(n -> "- " + toYaml(n).replace("\n", "\n  "))
             .collect(Collectors.joining("\n  "));
     }
 }

3.2 YAML → 模型(解析)

依赖 SnakeYAML:

public class FlowYamlReader {
     public static TxtNode fromYaml(String yaml) {
         Yaml parser = new Yaml();
         Object obj = parser.load(yaml);
         return parseNode(obj);
     }
 ​
     @SuppressWarnings("unchecked")
     private static TxtNode parseNode(Object obj) {
         if (obj instanceof String str) {
             return new TxtTask(str);
         } else if (obj instanceof Map map) {
             if (map.containsKey("series")) {
                 List<TxtNode> steps = ((List<?>) map.get("series"))
                     .stream().map(FlowYamlReader::parseNode)
                     .toList();
                 return new TxtSeries(steps);
             } else if (map.containsKey("parallel")) {
                 List<TxtNode> branches = ((List<?>) map.get("parallel"))
                     .stream().map(FlowYamlReader::parseNode)
                     .toList();
                 return new TxtParallel(branches);
             }
         }
         throw new IllegalArgumentException("Invalid node: " + obj);
     }
 }

4. 与 BPMN 的关系说明

本模型不兼容完整 BPMN。BPMN 是通用工作流标准,而“轻流”仅覆盖其最简子集。

可转换的 BPMN 片段示例

BPMN 中如下结构:

Start → A → [Parallel Gateway] → B & C → [Join Gateway] → D → End

可转换为:

series:
   - A                 # 串行第一步
   - parallel:         # 并行分支
       - B
       - C
   - D                 # 串行最后一步(等B、C都完成)

转换限制

  • 仅当 BPMN 流程不含条件网关(XOR)、循环、事件、子流程时可转换
  • 实际建议:用“轻流”描述主干逻辑,复杂路径仍由 BPMN 或代码处理

5. 适用场景 vs 局限

✅ 推荐使用

  • 自动化任务步骤配置(如数据导出、批处理)
  • CI/CD 流水线中的线性阶段
  • 微服务调用编排(无分支的 Saga 步骤)
  • 执行日志中的流程快照
  • API 文档中的调用序列说明

❌ 禁止使用

  • 含 if/else 判断的业务逻辑
  • 需要重试或循环的场景
  • 多级审批、加签、退回等人工流程
  • 依赖消息触发或定时事件的流程

总结

“轻流”是一种极简、文本优先的流程表达方案:

  • 核心结构:仅 series(串行)与 parallel(并行)
  • 文本格式:YAML 风格,可直接嵌入配置
  • Java 模型:统一 TxtNode 接口,支持 TxtTask / TxtSeries / TxtParallel
  • 能力边界:明确限定于无分支、无循环的简单流程

当你的流程可以用一句话描述清楚执行顺序时,“轻流”就是最佳表达方式。若需更复杂控制流,请回归代码或 BPMN——简单问题,简单解法

posted @ 2026-01-26 22:59  寻梦丄天涯  阅读(0)  评论(0)    收藏  举报