Acts workflow engine
acts is a fast, tiny, extensiable workflow engine, which provides the abilities to execute workflow based on yml model.
The yml workflow model is not as same as the tranditional workflow flow. such as bpmn. The yml format is inspired by Github actions. The main point of this workflow is to create a top abstraction to run the workflow logic and interact with the client via act node.
Every user's action can be regarded as a abstract act. these acts can be generated by some rules. such as for or catches.
This workflow engine focus on the workflow logics itself and message distributions. the complex business logic will be completed by act via the act message.
Key Features
Fast
Uses rust to create the lib, there is no virtual machine, no db dependencies. The feature local_store uses the rocksdb to make sure the store performance.
Running benches\workflow.rs start_workflow time: [842.58 µs 876.99 µs 912.59 µs]
Tiny
The lib size is only 3.5mb (no local_store), you can use Adapter to create external store.
Extensiable
Supports for extending the plugin Supports for creating external store
Installation
The easiest way to get the latest version of acts is to install it via cargo
Quickstart
- Start the workflow engine by
engine.start. - Load a yaml model to create a
workflow. - Deploy the model in step 2 by
engine.manager(). - Config events by
engine.emitter(). - Start the workflow by
engine.executor().
use ;
async
Examples
Please see examples
Model Usage
The model uses the yaml file to create, there are different type of node, which is constructed by [Workflow], [Branch], [Step] and [Act]. Every workflow can have more more steps, a step can have more branches and a branch can have if property to judge the condition.
The env property can be set the initialzed vars in workflow, in the step's run scripts, you can use env moudle to get(env.get) or set(env.set) the value
The run property is the script based on rhai script
name: model name
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")
Outputs
In the [Workflow], you can set the outputs to output the env to use.
name: model name
outputs:
output_key:
steps:
- name: step1
run: |
env.set("output_key", "output value");
Actions
Add workflow actions to create custom event with client
name: model name
actions:
- name: fn1
id: fn1
on:
- state: created
nkind: workflow
- state: completed
nkind: workflow
- name: fn2
id: fn2
on:
- state: completed
nid: step2
- name: fn3
id: fn3
on:
- state: completed
nid: step3
inputs:
a: ${ env.get("value") }
steps:
- name: step1
- name: step2
- name: step3
Steps
Use steps to add step to the workflow
name: model name
steps:
- id: step1
name: step 1
- id: step2
name: step 2
Branches
Use branches to add branch to the step
name: model name
steps:
- id: step1
name: step 1
branches:
- id: b1
if: env.get("v") > 0
steps:
- name: step a
- name: step b
- id: b2
else: true
steps:
- name: step c
- name: step d
- id: step2
name: step 2
Acts
Use acts to create act to interact with client
name: model name
outputs:
output_key:
steps:
- name: step1
acts:
- id: init
name: my act init
inputs:
a: 6
outputs:
c:
1. for
There is a example to use for to generate acts, which can wait util calling the action to complete.
name: model name
steps:
- name: step1
acts:
- for:
by: any
in: |
let a = ["u1"];
let b = ["u2"];
a.union(b)
It will generate the user act and send message automationly according to the in collection.
The by tells the workflow how to pass the act. There are several by rules.
- by
-
all to match all of the acts to complete
-
any to match any of the acts to complete
-
some(rule) to match some acts by giving rule name. If there is some rule, it can also generate a some act to ask the client to pass or not.
-
ord or ord(rule) to generate the act one by one. If there is order rule, it can also generate a rule act to sort the collection.
- in A collection to generate the acts.
The code act.role("test_role") uses the role rule to get the users through the role test_role
in: |
let users = act.role("test_role");
users
The following code uses the relate rule to find the user's owner of the department (d.owner).
users: |
let users = act.relate("user(test_user).d.owner");
users
2. catches
Use the catches to capture the act error and start a new act to run.
name: a example to catch act error
id: catches
steps:
- name: prepare
id: prepare
acts:
- id: init
- name: step1
id: step1
acts:
- id: act1
catches:
- id: catch1
err: err1
- id: catch2
err: err2
- id: catch_others
- name: final
id: final