#workflow #engine #step #user #model #yaml #properties

bin+lib yao

一个快速、小巧、可扩展的工作流引擎

2 个版本

0.1.4 2023年1月3日
0.1.0 2022年11月23日

#14#property

MIT 许可证

250KB
6.5K SLoC

姚工作流引擎

yao 是一个快速、小巧、可扩展的工作流引擎,它提供了基于简单的 yml 模型的执行工作流的能力。

yml 工作流模型与传统流程(如 bpmn)不同。它受到 Github actions 的启发。作为对比,它增加了分支定义以支持更复杂的流程,为了业务审批流程,它在步骤中定义了 subject 属性以支持用户、组织和角色的顶级绝对规则。

快速

使用 Rust 创建库,没有虚拟机,没有数据库依赖。默认存储使用 rocksdb 进行本地存储。

小巧

库的大小仅为 3MB(不包含本地数据库)

可扩展

支持插件来扩展功能

示例

以下是一些示例

如何启动

首先,您应该加载一个 ymal 工作流模型,并调用 engine.start 来启动,并调用 engine.close 来停止它。

use yao::{Engine, Vars, Workflow};

#[tokio::main]
async fn main() {
    let engine = Engine::new();

    let text = include_str!("../examples/simple/model.yml");
    let mut workflow = Workflow::from_str(text).unwrap();
    let mut vars = Vars::new();
    vars.insert("input".into(), 3.into());
    workflow.set_env(vars);

    engine.push(&workflow);

    let e = engine.clone();
    engine.on_workflow_complete(move |w: &Workflow| {
        println!(
            "on_workflow_complete: {:?}, cost={}ms",
            w.outputs(),
            w.cost()
        );
        e.close();
    });
    engine.start().await;
}

如何创建模型

注意 yaml 的结构,有不同类型的节点,由 WorkflowJobBranchStep 构建。每个工作流可以有更多作业,每个作业可以有更多步骤,每个步骤可以有更多分支,并且分支可以有 if 属性来判断条件。

可以在每个节点中设置 env 属性,在 run 脚本中,您可以使用 env 模块来获取(env.get)或设置(env.set)值。

run 属性是基于 rhai 脚本的。

name: model name
jobs:
  - id: job1
    env:
      value: 0
    steps:
      - name: step 1
        run: |
          print("step 1")

      - name: step 2
        branches:
          - name: branch 1
            if: ${ env.get("value") > 100 }
            run: |
                print("branch 1");

          - name: branch 2
            if: ${ env.get("value") <= 100 }
            steps:
                - name: step 3
                  run: |
                    print("branch 2")
            

Workflow 中,您可以设置 outputs 来输出可用的环境。

name: model name
outputs:
  output_key:
jobs:
  - id: job1
    steps:
      - name: step1
        run: |
          env.set("output_key", "output value");

subject 用于创建用户 [Act],它可以等待用户调用 post_message 完成操作。

name: model name
jobs:
  - id: job1
    steps:
      - name: step1
        subject: 
            matcher: any
            users: |
                let a = ["u1"];
                let b = ["u2"];
                a.union(b)

它将根据子用户自动生成用户操作并发送消息。当您向工作流发送 post_message 时,matcher 告诉工作流如何传递步骤操作,有几个匹配规则。

  • matcher
  1. one 仅生成或检查一个用户

  2. any 用于匹配任何用户

  3. some(rule_name) 通过提供规则名称来匹配一些用户,该规则名称可以通过 register_some_rule 函数进行注册。

  4. ordord(rule_name) 通过提供规则名称逐个生成活动消息,该规则名称可以通过 register_ord_rule 函数进行注册。

  • users 用于生成步骤参与者,最终结果是用户 ID,这些 ID 可以通过 org 或 role 规则生成。

以下代码 role("test_role") 使用规则来获取角色 test_role 中的用户。

users: |
    let users = role("test_role");
    users

以下代码使用 user("test_user") 获取用户,然后通过 relate 规则找到部门的用户拥有者(d.owner)。

users: |
    let users = user("test_user").relate("d.owner");
    users

使用构建器创建模型

use yao::{Workflow};

let mut workflow = Workflow::new()
        .with_name("workflow builder")
        .with_output("result", 0.into())
        .with_job(|job| {
            job.with_id("job1")
                .with_env("index", 0.into())
                .with_env("result", 0.into())
                .with_step(|step| {
                    step.with_id("cond")
                        .with_branch(|branch| {
                            branch
                                .with_if(r#"env.get("index") <= env.get("count")"#)
                                .with_step(|step| {
                                    step.with_id("c1")
                                        .with_action(|env| {
                                            let result =
                                                env.get("result").unwrap().as_i64().unwrap();
                                            let index = env.get("index").unwrap().as_i64().unwrap();
                                            env.set("result", (result + index).into());
                                            env.set("index", (index + 1).into());
                                        })
                                        .with_next("cond")
                                })
                        })
                        .with_branch(|branch| {
                            branch.with_if(r#"env.get("index") > env.get("count")"#)
                        })
                })
                .with_step(|step| {
                    step.with_name("step2")
                        .with_action(|env| println!("result={:?}", env.get("result").unwrap()))
                })
        });

注册插件

请参阅 ActPlugin 的示例。

注册存储适配器

请参阅 StoreAdapter 的示例。

注册组织适配器

请参阅 OrgAdapter 的示例。

注册角色适配器

请参阅 RoleAdapter 的示例。

注册规则适配器

请参阅 RuleAdapter 的示例。

依赖项

~76MB
~1.5M SLoC