Skip to content

Commit 35e13d5

Browse files
author
Tihomir Surdilovic
authored
Closes #239: Add SubFlow state repeat ability (#243)
* Add SubFlow state repeat ability Signed-off-by: Tihomir Surdilovic <[email protected]> * fix car vitals check example Signed-off-by: Tihomir Surdilovic <[email protected]> * fix example Signed-off-by: Tihomir Surdilovic <[email protected]> * fixes for comments Signed-off-by: Tihomir Surdilovic <[email protected]>
1 parent f93fedb commit 35e13d5

File tree

5 files changed

+376
-6
lines changed

5 files changed

+376
-6
lines changed

examples/README.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Provides Serverless Workflow language examples
2424
- [New Patient Onboarding (Error checking and Retries)](#New-Patient-Onboarding)
2525
- [Purchase order deadline (ExecTimeout)](#Purchase-order-deadline)
2626
- [Accumulate room readings and create timely reports (ExecTimeout and KeepActive)](#Accumulate-room-readings)
27+
- [Car vitals checks (SubFlow state Repeat)](#Car-Vitals-Checks)
2728

2829
### Hello World Example
2930

@@ -3241,3 +3242,253 @@ functions:
32413242
</td>
32423243
</tr>
32433244
</table>
3245+
3246+
### Car Vitals Checks
3247+
3248+
#### Description
3249+
3250+
In this example we need to check car vital signs while our car is driving.
3251+
The workflow should start when we receive the "carOn" event and stop when the "carOff" event is consumed.
3252+
While the car is driving our workflow should repeatedly check the vitals every 2 minutes.
3253+
3254+
For this example we use the workflow [SubFlow](../specification.md#SubFlow-State) state and its
3255+
[repeat definition](../specification.md#Repeat-Definition) to repeat execution of the vitals checks.
3256+
3257+
#### Workflow Diagram
3258+
3259+
<p align="center">
3260+
<img src="../media/examples/example-checkcarvitals.png" height="550px" alt="Check Car Vitals Example"/>
3261+
</p>
3262+
3263+
#### Workflow Definition
3264+
3265+
We fist define our top-level workflow for this example:
3266+
3267+
<table>
3268+
<tr>
3269+
<th>JSON</th>
3270+
<th>YAML</th>
3271+
</tr>
3272+
<tr>
3273+
<td valign="top">
3274+
3275+
```json
3276+
{
3277+
"id": "checkcarvitals",
3278+
"name": "Check Car Vitals Workflow",
3279+
"version": "1.0",
3280+
"states": [
3281+
{
3282+
"name": "WhenCarIsOn",
3283+
"type": "event",
3284+
"start": true,
3285+
"onEvents": [
3286+
{
3287+
"eventRefs": ["CarTurnedOnEvent"]
3288+
}
3289+
],
3290+
"transition": "DoCarVitalsChecks"
3291+
},
3292+
{
3293+
"name": "DoCarVitalsChecks",
3294+
"type": "subflow",
3295+
"workflowId": "vitalscheck",
3296+
"repeat": {
3297+
"stopOnEvents": ["CarTurnedOffEvent"]
3298+
},
3299+
"end": true
3300+
}
3301+
],
3302+
"events": [
3303+
{
3304+
"name": "CarTurnedOnEvent",
3305+
"type": "car.events",
3306+
"source": "my/car/start"
3307+
},
3308+
{
3309+
"name": "CarTurnedOffEvent",
3310+
"type": "car.events",
3311+
"source": "my/car/start"
3312+
}
3313+
]
3314+
}
3315+
```
3316+
3317+
</td>
3318+
<td valign="top">
3319+
3320+
```yaml
3321+
id: checkcarvitals
3322+
name: Check Car Vitals Workflow
3323+
version: '1.0'
3324+
states:
3325+
- name: WhenCarIsOn
3326+
type: event
3327+
start: true
3328+
onEvents:
3329+
- eventRefs:
3330+
- CarTurnedOnEvent
3331+
transition: DoCarVitalsChecks
3332+
- name: DoCarVitalsChecks
3333+
type: subflow
3334+
workflowId: vitalscheck
3335+
repeat:
3336+
stopOnEvents:
3337+
- CarTurnedOffEvent
3338+
end: true
3339+
events:
3340+
- name: CarTurnedOnEvent
3341+
type: car.events
3342+
source: my/car/start
3343+
- name: CarTurnedOffEvent
3344+
type: car.events
3345+
source: my/car/start
3346+
```
3347+
3348+
</td>
3349+
</tr>
3350+
</table>
3351+
3352+
And then our reusable sub-workflow which performs the checking of our car vitals:
3353+
3354+
<table>
3355+
<tr>
3356+
<th>JSON</th>
3357+
<th>YAML</th>
3358+
</tr>
3359+
<tr>
3360+
<td valign="top">
3361+
3362+
```json
3363+
{
3364+
"id": "vitalscheck",
3365+
"name": "Car Vitals Check",
3366+
"version": "1.0",
3367+
"states": [
3368+
{
3369+
"name": "CheckVitals",
3370+
"type": "operation",
3371+
"start": true,
3372+
"actions": [
3373+
{
3374+
"functionRef": "checkTirePressure"
3375+
},
3376+
{
3377+
"functionRef": "checkOilPressure"
3378+
},
3379+
{
3380+
"functionRef": "checkCoolantLevel"
3381+
},
3382+
{
3383+
"functionRef": "checkBattery"
3384+
}
3385+
],
3386+
"transition": "EvaluateChecks"
3387+
},
3388+
{
3389+
"name": "EvaluateChecks",
3390+
"type": "switch",
3391+
"dataConditions": [
3392+
{
3393+
"name": "Some Evaluations failed",
3394+
"condition": "$.evaluations[?(@.check == 'failed')]",
3395+
"end": {
3396+
"produceEvents": [
3397+
{
3398+
"eventRef": "DisplayFailedChecksOnDashboard",
3399+
"data": "{{ $.evaluations }}"
3400+
}
3401+
]
3402+
3403+
}
3404+
}
3405+
],
3406+
"default": {
3407+
"transition": "WaitTwoMinutes"
3408+
}
3409+
},
3410+
{
3411+
"name": "WaitTwoMinutes",
3412+
"type": "delay",
3413+
"timeDelay": "PT2M",
3414+
"end": true
3415+
}
3416+
],
3417+
"events": [
3418+
{
3419+
"name": "DisplayFailedChecksOnDashboard",
3420+
"kind": "produced",
3421+
"type": "my.car.events"
3422+
}
3423+
],
3424+
"functions": [
3425+
{
3426+
"name": "checkTirePressure",
3427+
"operation": "mycarservices.json#checktirepressure"
3428+
},
3429+
{
3430+
"name": "checkOilPressure",
3431+
"operation": "mycarservices.json#checkoilpressure"
3432+
},
3433+
{
3434+
"name": "checkCoolantLevel",
3435+
"operation": "mycarservices.json#checkcoolantlevel"
3436+
},
3437+
{
3438+
"name": "checkBattery",
3439+
"operation": "mycarservices.json#checkbattery"
3440+
}
3441+
]
3442+
}
3443+
```
3444+
3445+
</td>
3446+
<td valign="top">
3447+
3448+
```yaml
3449+
id: vitalscheck
3450+
name: Car Vitals Check
3451+
version: '1.0'
3452+
states:
3453+
- name: CheckVitals
3454+
type: operation
3455+
start: true
3456+
actions:
3457+
- functionRef: checkTirePressure
3458+
- functionRef: checkOilPressure
3459+
- functionRef: checkCoolantLevel
3460+
- functionRef: checkBattery
3461+
transition: EvaluateChecks
3462+
- name: EvaluateChecks
3463+
type: switch
3464+
dataConditions:
3465+
- name: Some Evaluations failed
3466+
condition: "$.evaluations[?(@.check == 'failed')]"
3467+
end:
3468+
produceEvents:
3469+
- eventRef: DisplayFailedChecksOnDashboard
3470+
data: "{{ $.evaluations }}"
3471+
default:
3472+
transition: WaitTwoMinutes
3473+
- name: WaitTwoMinutes
3474+
type: delay
3475+
timeDelay: PT2M
3476+
end: true
3477+
events:
3478+
- name: DisplayFailedChecksOnDashboard
3479+
kind: produced
3480+
type: my.car.events
3481+
functions:
3482+
- name: checkTirePressure
3483+
operation: mycarservices.json#checktirepressure
3484+
- name: checkOilPressure
3485+
operation: mycarservices.json#checkoilpressure
3486+
- name: checkCoolantLevel
3487+
operation: mycarservices.json#checkcoolantlevel
3488+
- name: checkBattery
3489+
operation: mycarservices.json#checkbattery
3490+
```
3491+
3492+
</td>
3493+
</tr>
3494+
</table>
336 KB
Loading

roadmap/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ _Status description:_
3131
| ✔️| Simplified functionRef and transition properties | [spec doc](../specification.md) |
3232
| ✔️| Adding comparison examples with Cadence | [comparison doc](../comparisons/README.md) |
3333
| ✔️| Adding workflow execTimeout and keepActive properties | [spec doc](../specification.md) |
34+
| ✔️| Adding SubFlow state repeat (loop) ability | [spec doc](../specification.md) |
3435
| 🚩 | JSONPatch transformations | [issue](https://github.com/serverlessworkflow/specification/issues/149) |
3536
| 🚩 | Workflow invocation bindings | |
3637
| 🚩 | CE Subscriptions & Discovery | |

schema/workflow.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,10 @@
13071307
"type": "string",
13081308
"description": "Sub-workflow unique id"
13091309
},
1310+
"repeat": {
1311+
"$ref": "#/definitions/repeat",
1312+
"description": "SubFlow state repeat exec definition"
1313+
},
13101314
"stateDataFilter": {
13111315
"$ref": "#/definitions/statedatafilter"
13121316
},
@@ -1980,6 +1984,39 @@
19801984
}
19811985
},
19821986
"required": []
1987+
},
1988+
"repeat": {
1989+
"type": "object",
1990+
"properties": {
1991+
"expression": {
1992+
"type": "string",
1993+
"description": "Expression evaluated against SubFlow state data. SubFlow will repeat execution as long as this expression is true or until the max property count is reached",
1994+
"minLength": 1
1995+
},
1996+
"checkBefore": {
1997+
"type": "boolean",
1998+
"description": "If true, the expression is evaluated before each repeat execution, if false the expression is evaluated after each repeat execution",
1999+
"default": true
2000+
},
2001+
"max": {
2002+
"type": "integer",
2003+
"description": "Sets the maximum amount of repeat executions",
2004+
"minimum": 0
2005+
},
2006+
"continueOnError": {
2007+
"type": "boolean",
2008+
"description": "If true, repeats executions in a case unhandled errors propagate from the sub-workflow to this state",
2009+
"default": false
2010+
},
2011+
"stopOnEvents": {
2012+
"type" : "array",
2013+
"description": "List referencing defined consumed workflow events. SubFlow will repeat execution until one of the defined events is consumed, or until the max property count is reached",
2014+
"minItems": 1,
2015+
"items": {
2016+
"type": "string"
2017+
}
2018+
}
2019+
}
19832020
}
19842021
}
19852022
}

0 commit comments

Comments
 (0)