Skip to content

Commit 6879277

Browse files
Adding ContinueAs Example (#507)
* Adding ContinueAs Example Signed-off-by: Tihomir Surdilovic <[email protected]> * formatting Signed-off-by: Tihomir Surdilovic <[email protected]> * update to roadmap Signed-off-by: Tihomir Surdilovic <[email protected]> * Update examples/README.md Co-authored-by: Ricardo Zanini <[email protected]> * Update examples/README.md Co-authored-by: Ricardo Zanini <[email protected]> * Update specification.md Co-authored-by: Ricardo Zanini <[email protected]> Co-authored-by: Ricardo Zanini <[email protected]>
1 parent e15b865 commit 6879277

File tree

4 files changed

+169
-2
lines changed

4 files changed

+169
-2
lines changed

examples/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Provides Serverless Workflow language examples
2828
- [Book Lending Workflow](#Book-Lending)
2929
- [Filling a glass of water (Expression functions)](#Filling-a-glass-of-water)
3030
- [Online Food Ordering](#Online-Food-Ordering)
31+
- [Online Food Ordering](#Online-Food-Ordering)
32+
- [Continuing as a new Execution](#Continuing-as-a-new-Execution)
3133

3234
### Hello World Example
3335

@@ -4234,3 +4236,163 @@ For the example order event, the workflow output for a successful completion wou
42344236
]
42354237
}
42364238
```
4239+
4240+
### Continuing as a new Execution
4241+
4242+
#### Description
4243+
4244+
Some runtime implementations on which we run our workflows can have different quotas, such as maximum execution durations, maximum consumed events, etc. We can use the Serverless workflow "continueAs" functionality that can be used to stop the current workflow execution and start another one (of the same or a different type). This is very useful in cases where we have to ensure we don't reach the imposed quotas of single workflow execution.
4245+
4246+
This example assumes that the runtime we are using has a quota set to a maximum of one thousand consumed events per single workflow execution.
4247+
Our sample workflow consumes a single customer event at a time and invokes the `emailCustomer` function.
4248+
Note that we do not set a workflow `workflowExecTimeout`, so we intend to have a long-running workflow. However, because of the runtime restriction, in this case, we would run into the event consume limit, and our workflow would have to terminate. We can fix this problem by using [`continueAs`](../specification.md#Continuing-as-a-new-Execution), which will allow us to make sure that we reach the given limit and then continue our workflow execution as a new run.
4249+
4250+
We assume that our workflow input has the runtime-imposed quota:
4251+
4252+
```json
4253+
{
4254+
"quota": {
4255+
"maxConsumedEvents": 1000
4256+
}
4257+
}
4258+
```
4259+
4260+
#### Workflow Diagram
4261+
4262+
<p align="center">
4263+
<img src="../media/examples/example-continueas.png" height="400px" alt="ContinueAs Example"/>
4264+
</p>
4265+
4266+
#### Workflow Definition
4267+
4268+
<table>
4269+
<tr>
4270+
<th>JSON</th>
4271+
<th>YAML</th>
4272+
</tr>
4273+
<tr>
4274+
<td valign="top">
4275+
4276+
```json
4277+
{
4278+
"id":"notifycustomerworkflow",
4279+
"name":"Notify Customer",
4280+
"version":"1.0",
4281+
"specVersion":"0.7",
4282+
"start":"WaitForCustomerEvent",
4283+
"states":[
4284+
{
4285+
"name":"WaitForCustomerEvent",
4286+
"type":"event",
4287+
"onEvents":[
4288+
{
4289+
"eventRefs":[
4290+
"CustomerEvent"
4291+
],
4292+
"eventDataFilter":{
4293+
"data":"${ .customerId }",
4294+
"toStateData":"${ .eventCustomerId }"
4295+
},
4296+
"actions":[
4297+
{
4298+
"functionRef":{
4299+
"refName":"NotifyCustomerFunction",
4300+
"arguments":{
4301+
"customerId":"${ .eventCustomerId }"
4302+
}
4303+
}
4304+
}
4305+
]
4306+
}
4307+
],
4308+
"stateDataFilter":{
4309+
"output":"${ .count = .count + 1 }"
4310+
},
4311+
"transition":"CheckEventQuota"
4312+
},
4313+
{
4314+
"name":"CheckEventQuota",
4315+
"type":"switch",
4316+
"dataConditions":[
4317+
{
4318+
"condition":"${ try(.customerCount) != null and .customerCount > .quota.maxConsumedEvents }",
4319+
"end":{
4320+
"continueAs": {
4321+
"workflowId": "notifycustomerworkflow",
4322+
"version": "1.0",
4323+
"data": "${ del(.customerCount) }"
4324+
}
4325+
}
4326+
}
4327+
],
4328+
"defaultCondition":{
4329+
"transition":"WaitForCustomerEvent"
4330+
}
4331+
}
4332+
],
4333+
"events":[
4334+
{
4335+
"name":"CustomerEvent",
4336+
"type":"org.events.customerEvent",
4337+
"source":"customerSource"
4338+
}
4339+
],
4340+
"functions":[
4341+
{
4342+
"name":"NotifyCustomerFunction",
4343+
"operation":"http://myapis.org/customerapis.json#notifyCustomer"
4344+
}
4345+
]
4346+
}
4347+
```
4348+
4349+
</td>
4350+
<td valign="top">
4351+
4352+
```yaml
4353+
id: notifycustomerworkflow
4354+
name: Notify Customer
4355+
version: '1.0'
4356+
specVersion: '0.7'
4357+
start: WaitForCustomerEvent
4358+
states:
4359+
- name: WaitForCustomerEvent
4360+
type: event
4361+
onEvents:
4362+
- eventRefs:
4363+
- CustomerEvent
4364+
eventDataFilter:
4365+
data: "${ .customerId }"
4366+
toStateData: "${ .eventCustomerId }"
4367+
actions:
4368+
- functionRef:
4369+
refName: NotifyCustomerFunction
4370+
arguments:
4371+
customerId: "${ .eventCustomerId }"
4372+
stateDataFilter:
4373+
output: "${ .count = .count + 1 }"
4374+
transition: CheckEventQuota
4375+
- name: CheckEventQuota
4376+
type: switch
4377+
dataConditions:
4378+
- condition: "${ try(.customerCount) != null and .customerCount > .quota.maxConsumedEvents
4379+
}"
4380+
end:
4381+
continueAs:
4382+
workflowId: notifycustomerworkflow
4383+
version: '1.0'
4384+
data: "${ del(.customerCount) }"
4385+
defaultCondition:
4386+
transition: WaitForCustomerEvent
4387+
events:
4388+
- name: CustomerEvent
4389+
type: org.events.customerEvent
4390+
source: customerSource
4391+
functions:
4392+
- name: NotifyCustomerFunction
4393+
operation: http://myapis.org/customerapis.json#notifyCustomer
4394+
```
4395+
4396+
</td>
4397+
</tr>
4398+
</table>

media/examples/example-continueas.png

82.2 KB
Loading

roadmap/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ _Status description:_
2828
| ✔️| ForEach state "iterationParam" no longer a required property | [spec doc](https://github.com/serverlessworkflow/specification/blob/main/specification.md) |
2929
| ✔️| Added "useData" for eventDataFilter, and "useResults" for actionDataFilter | [spec doc](https://github.com/serverlessworkflow/specification/blob/main/specification.md) |
3030
| ✔️| Added "resultEventTimeout" for action eventref | [spec doc](https://github.com/serverlessworkflow/specification/blob/main/specification.md) |
31+
| ✔️| Added example for "continueAs" | [examples doc](https://github.com/serverlessworkflow/specification/blob/main/examples/README.md) |
3132
| ✏️️| Support for async action invocation | |
3233
| ✏️️| Add "completedBy" functionality | |
3334
| ✏️️| Define workflow context | |

specification.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,7 +2278,7 @@ the state should transition to the next state or can end the workflow execution
22782278

22792279
The `timeouts` property can be used to define state specific timeout settings. Event states can define the
22802280
`stateExecTimeout`, `actionExecTimeout`, and `eventTimeout` properties.
2281-
For more information about Event state specific event timeout settings reference [this section](#Event Timeout Definition).
2281+
For more information about Event state specific event timeout settings reference [this section](#Event-Timeout-Definition).
22822282
For more information about workflow timeouts reference the [Workflow Timeouts](#Workflow-Timeouts) section.
22832283

22842284
##### Operation State
@@ -4769,7 +4769,7 @@ is reached.
47694769
The [compensate](#Workflow-Compensation) property defines that workflow compensation should be performed before the workflow
47704770
execution is completed.
47714771

4772-
The [continueAs](#Continuing as a new Execution) property defines that the current workflow instance should stop its execution,
4772+
The [continueAs](#Continuing-as-a-new-Execution) property defines that the current workflow instance should stop its execution,
47734773
and worklow execution should continue as a new instance of a new workflow.
47744774
When defined, it should be assumed that `terminate` is `true`. If `continueAs` is defined, and `terminate` is explicitly
47754775
set to false, runtimes should report this to users. Producing events, and compensation should still be performed (if defined)
@@ -5786,6 +5786,10 @@ End definitions can trigger compensations by specifying the `compensate` propert
57865786
This means that before workflow finishes its execution workflow compensation must be performed. Note that
57875787
in case when the end definition has its `produceEvents` property set, compensation must be performed before
57885788
producing the specified events and ending workflow execution.
5789+
In the case the end definition has a `continueAs` property defined, compensation must be performed before
5790+
workflow execution continues as a new workflow invocation.
5791+
In the case where the end definition has both `produceEvents`, and `continueAs` compensation is performed first,
5792+
then the event should be produced, and then the workflow should continue its execution as a new workflow invocation.
57895793

57905794
#### Compensation Execution Details
57915795

0 commit comments

Comments
 (0)