Closed
Description
What would you like to be added:
I propose to:
- only use the
continue
FlowDirective to continue a loop - make
then
required in all tasks - add a
start
field to the workflow that denotes the first task to execute
document:
dsl: '1.0.0-alpha1'
namespace: test
name: order-pet
version: '1.0.0'
title: Order Pet - 1.0.0
summary: >
# Order Pet - 1.0.0
## Table of Contents
- [Description](#description)
- [Requirements](#requirements)
## Description
A sample workflow used to process an hypothetic pet order using the [PetStore API](https://petstore.swagger.io/)
## Requirements
### Secrets
- my-oauth2-secret
use:
authentications:
petStoreOAuth2:
oauth2: my-oauth2-secret
functions:
getAvailablePets:
call: openapi
with:
document:
uri: https://petstore.swagger.io/v2/swagger.json
operation: findByStatus
parameters:
status: available
secrets:
- my-oauth2-secret
start: getAvailablePets
do:
getAvailablePets:
call: getAvailablePets
output:
from: "$input + { availablePets: [.[] | select(.category.name == "dog" and (.tags[] | .breed == $input.order.breed))] }"
then: submitMatchesByMail
submitMatchesByMail:
call: http
with:
method: post
endpoint:
uri: https://fake.smtp.service.com/email/send
authentication: petStoreOAuth2
body:
from: noreply@fake.petstore.com
to: ${ .order.client.email }
subject: Candidates for Adoption
body: >
Hello ${ .order.client.preferredDisplayName }!
Following your interest to adopt a dog, here is a list of candidates that you might be interested in:
${ .pets | map("-\(.name)") | join("\n") }
Please do not hesistate to contact us at info@fake.petstore.com if your have questions.
Hope to hear from you soon!
----------------------------------------------------------------------------------------------
DO NOT REPLY
----------------------------------------------------------------------------------------------
then: end
Why is this needed:
Currently the task execution order is determined by the order in which the tasks appear in the "do" field.
This is very convenient for writing small workflows.
I however see two mayor drawbacks with this approach:
- similar problems as with a "switch fallthrough". If one forgets a "then" field the execution might resume at a task that is different from the one I expected.
Another interesting case is that the then
field is allowed top level in switch
tasks. So The way I understand it, this would execute the processElectronicOrder
task when the default case is reached because it sets a continue
clause.
document:
dsl: '1.0.0-alpha1'
namespace: test
name: sample-workflow
version: '0.1.0'
do:
processOrder:
switch:
case1:
when: .orderType == "electronic"
then: processElectronicOrder
case2:
when: .orderType == "physical"
then: processPhysicalOrder
default:
then: continue
processElectronicOrder:
execute:
sequentially:
validatePayment: {...}
fulfillOrder: {...}
then: exit
processPhysicalOrder:
execute:
sequentially:
checkInventory: {...}
packItems: {...}
scheduleShipping: {...}
then: exit
handleUnknownOrderType:
execute:
sequentially:
logWarning: {...}
notifyAdmin: {...}
- reliance on object keys forces implementers to alway process/store definitions as text blobs or strings.
Some problems this causes:
- One cannot store the definition as a JSON object in SQL or NoSQL databases as they usually do not preserve Object key order. Thus one cannot use built-in filtering in databases
- When building an API to create workflows the definition has to be accepted as a string or file blob then parsed and validated with the JSON schema and then the parsed object cannot be used because key order is not preserved. This might look something like this in TypeScript:
function parse(input: string): IDefinition {
const obj: Workflow = JSON.parse(input);
validate(obj);
// parse document as map
const map: Map<"do", Map<string, Task>> = yaml.parse(input, {
mapAsMap: true,
});
// get task names in order of appearance
const taskNames = Array.from(map.get("do")?.keys() ?? []);
const tasks = new Map<string, Task>();
taskNames.forEach((name) => {
// get task as object instead of Map
const task = obj.do[name];
if (task) {
tasks.set(name, task);
}
});
return { ...obj, do: tasks, text: input };
}
and this only works because Map
keys preserve order of insertion, assuming that yaml
never changes the implementation that would change the insertion order.
- when providing a UI to build/visualize workflows the logic to create a valid and correct workflow definition might become incredible complex because on has to be precise about the ordering of keys, handle exit and fallthrough cases etc...
Metadata
Metadata
Assignees
Type
Projects
Status
Done