# Examples ## Table of Contents - [Hello World](#Hello-World-Example) - [Greeting](#Greeting-Example) - [Event-based greeting](#Event-Based-Greeting-Example) - [Solving Math Problems (ForEach state)](#Solving-Math-Problems-Example) - [Parallel Execution](#Parallel-Execution-Example) - [Applicant Request Decision (Switch + SubFlow states)](#Applicant-Request-Decision-Example) - [Provision Orders (Error Handling)](#Provision-Orders-Example) - [Monitor Job for completion (Polling)](#Monitor-Job-Example) - [Send CloudEvent on Workflow Completion](#Send-CloudEvent-On-Workfow-Completion-Example) - [Monitor Patient Vital Signs (Event state)](#Monitor-Patient-Vital-Signs-Example) - [Finalize College Application (Event state)](#Finalize-College-Application-Example) - [Perform Customer Credit Check (Callback state)](#Perform-Customer-Credit-Check-Example) - [Handle Car Auction Bids (Scheduled start Event state)](#Handle-Car-Auction-Bids-Example) ### Hello World Example #### Description This example uses two inject states. The "Hello" state statically injects the following JSON into its data input: ```json { "result": "Hello" } ``` which then becomes the data input of the transition "World" state. The "World" state merges its data input with it's injected JSON and uses a filter to set its data output to the value of the "result" property. Since it is an end state, it's data output becomes the workflow data output: ```text "Hello World!" ``` #### Workflow Definition
JSON YAML
```json { "id": "helloworld", "version": "1.0", "name": "Hello World Workflow", "description": "Static Hello World", "states":[ { "name":"Hello", "type":"INJECT", "start": { "kind": "DEFAULT" }, "data": { "result": "Hello" }, "transition": { "nextState": "World" } }, { "name":"World", "type":"INJECT", "data": { "result": " World!" }, "stateDataFilter": { "dataOutputPath": "$.result" }, "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: helloworld version: '1.0' name: Hello World Workflow description: Static Hello World states: - name: Hello type: INJECT start: kind: DEFAULT data: result: Hello transition: nextState: World - name: World type: INJECT data: result: " World!" stateDataFilter: dataOutputPath: "$.result" end: kind: DEFAULT ```
#### Workflow Diagram

Hello World Example

### Greeting Example #### Description This example shows a single Operation state with one action that calls the "greeting" function. The workflow data input is assumed to be the name of the person to greet: ```json { "greet": { "name": "John" } } ``` The results of the action is assumed to be the full greeting for the provided persons name: ```json { "payload": { "greeting": "Welcome to Serverless Workflow, John!" } } ``` The states action data filter selects the greeting object from the function return to be placed into the state data. Then the states state data filter selects only the greeting object to be returned as its data output, which becomes the workflow data output (as it is an end state): ```text "Welcome to Serverless Workflow, John!" ``` #### Workflow Definition
JSON YAML
```json { "id": "greeting", "version": "1.0", "name": "Greeting Workflow", "description": "Greet Someone", "functions": [ { "name": "greetingFunction", "resource": "functionResourse" } ], "states":[ { "name":"Greet", "type":"OPERATION", "start": { "kind": "DEFAULT" }, "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "greetingFunction", "parameters": { "name": "$.greet.name" } }, "actionDataFilter": { "dataResultsPath": "$.payload.greeting" } } ], "stateDataFilter": { "dataOutputPath": "$.greeting" }, "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: greeting version: '1.0' name: Greeting Workflow description: Greet Someone functions: - name: greetingFunction resource: functionResourse states: - name: Greet type: OPERATION start: kind: DEFAULT actionMode: SEQUENTIAL actions: - functionRef: refName: greetingFunction parameters: name: "$.greet.name" actionDataFilter: dataResultsPath: "$.payload.greeting" stateDataFilter: dataOutputPath: "$.greeting" end: kind: DEFAULT ```
#### Workflow Diagram

Greeting Example

### Event Based Greeting Example #### Description This example shows a single Event state with one action that calls the "greeting" function. The event state consumes cloud events of type "greetingEventType". When an even with this type is consumed, the Event state performs a single action that calls the defined "greeting" function. For the sake of the example we assume that the cloud event we will consume has the format: ```json { "specversion" : "1.0", "type" : "greetingEventType", "source" : "greetingEventSource", "data" : { "greet": { "name": "John" } } } ``` The results of the action is assumed to be the full greeting for the provided persons name: ```json { "payload": { "greeting": "Welcome to Serverless Workflow, John!" } } ``` Note that in the workflow definition you can see two filters defined. The event data filter defined inside the consume element: ```json { "eventDataFilter": { "dataOutputPath": "$.data.greet" } } ``` which is triggered when the greeting event is consumed. It extracts its "data.greet" of the event and merges it with the states data. The second, a state data filter, which is defined on the event state itself: ```json { "stateDataFilter": { "dataOutputPath": "$.payload.greeting" } } ``` filters what is selected to be the state data output which then becomes the workflow data output (as it is an end state): ```text "Welcome to Serverless Workflow, John!" ``` #### Workflow Definition
JSON YAML
```json { "id": "eventbasedgreeting", "version": "1.0", "name": "Event Based Greeting Workflow", "description": "Event Based Greeting", "events": [ { "name": "GreetingEvent", "type": "greetingEventType", "source": "greetingEventSource" } ], "functions": [ { "name": "greetingFunction", "resource": "functionResourse" } ], "states":[ { "name":"Greet", "type":"EVENT", "start": { "kind": "DEFAULT" }, "eventsActions": [{ "eventRefs": ["GreetingEvent"], "eventDataFilter": { "inputPath": "$.data.greet" }, "actions":[ { "functionRef": { "refName": "greetingFunction", "parameters": { "name": "$.greet.name" } } } ] }], "stateDataFilter": { "dataOutputPath": "$.payload.greeting" }, "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: eventbasedgreeting version: '1.0' name: Event Based Greeting Workflow description: Event Based Greeting events: - name: GreetingEvent type: greetingEventType source: greetingEventSource functions: - name: greetingFunction resource: functionResourse states: - name: Greet type: EVENT start: kind: DEFAULT eventsActions: - eventRefs: - GreetingEvent eventDataFilter: inputPath: "$.data.greet" actions: - functionRef: refName: greetingFunction parameters: name: "$.greet.name" stateDataFilter: dataOutputPath: "$.payload.greeting" end: kind: DEFAULT ```
#### Workflow Diagram

Event Based Greeting Example

### Solving Math Problems Example #### Description In this example we show how to iterate over some data input using the ForEach state. The state will iterate over a collection of simple math expressions which are passed in as the workflow data input: ```json { "expressions": ["2+2", "4-1", "10x3", "20/2"] } ``` The ForEach state will execute a single defined operation state for each math expression. The operation state contains an action which calls a serverless function which actually solves the expression and returns its result. Results of all math expressions are accumulated into the data output of the ForEach state which become the final result of the workflow execution. #### Workflow Definition
JSON YAML
```json { "id": "solvemathproblems", "version": "1.0", "name": "Solve Math Problems Workflow", "description": "Solve math problems", "functions": [ { "name": "solveMathExpressionFunction", "resource": "functionResourse" } ], "states":[ { "name":"Solve", "start": { "kind": "DEFAULT" }, "type":"FOREACH", "inputCollection": "$.expressions", "inputParameter": "$.singleexpression", "outputCollection": "$.results", "states": [ { "name":"GetResults", "type":"OPERATION", "start": { "kind": "DEFAULT" }, "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "solveMathExpressionFunction", "parameters": { "expression": "$.singleexpression" } } } ], "end": { "kind": "DEFAULT" } } ], "stateDataFilter": { "dataOutputPath": "$.results" }, "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: solvemathproblems version: '1.0' name: Solve Math Problems Workflow description: Solve math problems functions: - name: solveMathExpressionFunction resource: functionResourse states: - name: Solve start: kind: DEFAULT type: FOREACH inputCollection: "$.expressions" inputParameter: "$.singleexpression" outputCollection: "$.results" states: - name: GetResults type: OPERATION start: kind: DEFAULT actionMode: SEQUENTIAL actions: - functionRef: refName: solveMathExpressionFunction parameters: expression: "$.singleexpression" end: kind: DEFAULT stateDataFilter: dataOutputPath: "$.results" end: kind: DEFAULT ```
#### Workflow Diagram

Looping Example

### Parallel Execution Example #### Description This example uses a parallel state to execute two branches (simple wait states) at the same time. The completionType type is set to "AND", which means the parallel state has to wait for both branches to finish execution before it can transition (end workflow execution in this case as it is an end state). #### Workflow Definition
JSON YAML
```json { "id": "parallelexec", "version": "1.0", "name": "Parallel Execution Workflow", "description": "Executes two branches in parallel", "states":[ { "name":"ParallelExec", "type":"PARALLEL", "start": { "kind": "DEFAULT" }, "completionType": "AND", "branches": [ { "name": "Branch1", "states": [ { "name":"ShortDelay", "type":"DELAY", "start": { "kind": "DEFAULT" }, "timeDelay": "PT15S", "end": { "kind": "DEFAULT" } } ] }, { "name": "Branch2", "states": [ { "name":"LongDelay", "type":"DELAY", "start": { "kind": "DEFAULT" }, "timeDelay": "PT2M", "end": { "kind": "DEFAULT" } } ] } ], "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: parallelexec version: '1.0' name: Parallel Execution Workflow description: Executes two branches in parallel states: - name: ParallelExec type: PARALLEL start: kind: DEFAULT branches: completionType: AND - name: Branch1 states: - name: ShortDelay type: DELAY start: kind: DEFAULT timeDelay: PT15S end: kind: DEFAULT - name: Branch2 states: - name: LongDelay type: DELAY start: kind: DEFAULT timeDelay: PT2M end: kind: DEFAULT end: kind: DEFAULT ```
#### Workflow Diagram

Parallel Example

### Applicant Request Decision Example #### Description This example shows off the switch state and the subflow state. The workflow is started with application information data as input: ```json { "applicant": { "fname": "John", "lname": "Stockton", "age": 22, "email": "js@something.com" } } ``` We use the switch state with two conditions to determine if the application should be made based on the applicants age. If the applicants age is over 18 we start the application (subflow state). Otherwise the workflow notifies the applicant of the rejection. #### Workflow Definition
JSON YAML
```json { "id": "applicantrequest", "version": "1.0", "name": "Applicant Request Decision Workflow", "description": "Determine if applicant request is valid", "functions": [ { "name": "sendRejectionEmailFunction", "resource": "functionResourse" } ], "states":[ { "name":"CheckApplication", "type":"SWITCH", "start": { "kind": "DEFAULT" }, "conditions": [ { "path": "$.applicant.age", "value": "18", "operator": "GreaterThanOrEquals", "transition": { "nextState": "StartApplication" } }, { "path": "$.applicant.age", "value": "18", "operator": "LessThan", "transition": { "nextState": "RejectApplication" } } ], "default": { "nextState": "RejectApplication" } }, { "name": "StartApplication", "type": "SUBFLOW", "workflowId": "startApplicationWorkflowId", "end": { "kind": "DEFAULT" } }, { "name":"RejectApplication", "type":"OPERATION", "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "sendRejectionEmailFunction", "parameters": { "applicant": "$.applicant" } } } ], "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: applicantrequest version: '1.0' name: Applicant Request Decision Workflow description: Determine if applicant request is valid functions: - name: sendRejectionEmailFunction resource: functionResourse states: - name: CheckApplication type: SWITCH start: kind: DEFAULT conditions: - path: "$.applicant.age" value: '18' operator: GreaterThanOrEquals transition: nextState: StartApplication - path: "$.applicant.age" value: '18' operator: LessThan transition: nextState: RejectApplication default: nextState: RejectApplication - name: StartApplication type: SUBFLOW workflowId: startApplicationWorkflowId end: kind: DEFAULT - name: RejectApplication type: OPERATION actionMode: SEQUENTIAL actions: - functionRef: refName: sendRejectionEmailFunction parameters: applicant: "$.applicant" end: kind: DEFAULT ```
#### Workflow Diagram

Switch State Example

### Provision Orders Example #### Description In this example we show off the states error handling capability. The workflow data input that's passed in contains missing order information that causes the function in the "ProvisionOrder" state to throw a runtime exception. With the "onError" expression we can transition the workflow to different error handling states depending on the error thrown. Each type of error in this example is handled by simple delay states, each including an error data filter which sets the exception info as their data output. If no error is caught the workflow can transition to the "ApplyOrder" state. Workflow data is assumed to me: ```json { "order": { "id": "", "item": "laptop", "quantity": "10" } } ``` The data output of the workflow contains the information of the exception caught during workflow execution. #### Workflow Definition
JSON YAML
```json { "id": "provisionorders", "version": "1.0", "name": "Provision Orders", "description": "Provision Orders and handle errors thrown", "functions": [ { "name": "provisionOrderFunction", "resource": "functionResourse" } ], "states":[ { "name":"ProvisionOrder", "type":"OPERATION", "start": { "kind": "DEFAULT" }, "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "provisionOrderFunction", "parameters": { "order": "$.order" } } } ], "onError": [ { "expression": { "language": "spel", "body": "name eq 'MissingOrderIdException'" }, "transition": { "nextState": "MissingId" } }, { "expression": { "language": "spel", "body": "name eq 'MissingOrderItemException'" }, "transition": { "nextState": "MissingItem" } }, { "expression": { "language": "spel", "body": "name eq 'MissingOrderQuantityException'" }, "transition": { "nextState": "MissingQuantity" } } ], "stateDataFilter": { "dataOutputPath": "$.exception" }, "transition": { "nextState":"ApplyOrder" } }, { "name": "MissingId", "type": "SUBFLOW", "workflowId": "handleMissingIdExceptionWorkflow", "end": { "kind": "DEFAULT" } }, { "name": "MissingItem", "type": "SUBFLOW", "workflowId": "handleMissingItemExceptionWorkflow", "end": { "kind": "DEFAULT" } }, { "name": "MissingQuantity", "type": "SUBFLOW", "workflowId": "handleMissingQuantityExceptionWorkflow", "end": { "kind": "DEFAULT" } }, { "name": "ApplyOrder", "type": "SUBFLOW", "workflowId": "applyOrderWorkflowId", "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: provisionorders version: '1.0' name: Provision Orders description: Provision Orders and handle errors thrown functions: - name: provisionOrderFunction resource: functionResourse states: - name: ProvisionOrder type: OPERATION start: kind: DEFAULT actionMode: SEQUENTIAL actions: - functionRef: refName: provisionOrderFunction parameters: order: "$.order" onError: - expression: language: spel body: name eq 'MissingOrderIdException' transition: nextState: MissingId - expression: language: spel body: name eq 'MissingOrderItemException' transition: nextState: MissingItem - expression: language: spel body: name eq 'MissingOrderQuantityException' transition: nextState: MissingQuantity stateDataFilter: dataOutputPath: "$.exception" transition: nextState: ApplyOrder - name: MissingId type: SUBFLOW workflowId: handleMissingIdExceptionWorkflow end: kind: DEFAULT - name: MissingItem type: SUBFLOW workflowId: handleMissingItemExceptionWorkflow end: kind: DEFAULT - name: MissingQuantity type: SUBFLOW workflowId: handleMissingQuantityExceptionWorkflow end: kind: DEFAULT - name: ApplyOrder type: SUBFLOW workflowId: applyOrderWorkflowId end: kind: DEFAULT ```
#### Workflow Diagram

Handle Errors Example

### Monitor Job Example #### Description In this example we submit a job via an operation state action (serverless function call). It is assumed that it takes some time for the submitted job to complete and that it's completion can be checked via another separate serverless function call. To check for completion we first wait 5 seconds and then get the results of the "CheckJob" serverless function. Depending on the results of this we either return the results or transition back to waiting and checking the job completion. This is done until the job submission returns "SUCCEEDED" or "FAILED" and the job submission results are reported before workflow finishes execution. In the case job submission raises a runtime error, we transition to a SubFlow state which handles the job submission issue. #### Workflow Definition
JSON YAML
```json { "id": "jobmonitoring", "version": "1.0", "name": "Job Monitoring", "description": "Monitor finished execution of a submitted job", "functions": [ { "name": "submitJob", "resource": "submitJobResource" }, { "name": "checkJobStatus", "resource": "checkJobStatusResource" }, { "name": "reportJobSuceeded", "resource": "reportJobSuceededResource" }, { "name": "reportJobFailed", "resource": "reportJobFailedResource" } ], "states":[ { "name":"SubmitJob", "type":"OPERATION", "start": { "kind": "DEFAULT" }, "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "submitJob", "parameters": { "name": "$.job.name" } }, "actionDataFilter": { "dataResultsPath": "$.jobuid" } } ], "onError": [ { "expression": { "language": "spel", "body": "$.exception != null" }, "errorDataFilter": { "dataOutputPath": "$.exception" }, "transition": { "nextState": "SubmitError" } } ], "stateDataFilter": { "dataOutputPath": "$.jobuid" }, "transition": { "nextState":"WaitForCompletion" } }, { "name": "SubmitError", "type": "SUBFLOW", "workflowId": "handleJobSubmissionErrorWorkflow", "end": { "kind": "DEFAULT" } }, { "name": "WaitForCompletion", "type": "DELAY", "timeDelay": "PT5S", "transition": { "nextState":"GetJobStatus" } }, { "name":"GetJobStatus", "type":"OPERATION", "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "checkJobStatus", "parameters": { "name": "$.jobuid" } }, "actionDataFilter": { "dataResultsPath": "$.jobstatus" } } ], "stateDataFilter": { "dataOutputPath": "$.jobstatus" }, "transition": { "nextState":"DetermineCompletion" } }, { "name":"DetermineCompletion", "type":"SWITCH", "conditions": [ { "path": "$.jobstatus", "value": "SUCCEEDED", "operator": "Equals", "transition": { "nextState": "JobSucceeded" } }, { "path": "$.jobstatus", "value": "FAILED", "operator": "Equals", "transition": { "nextState": "JobFailed" } } ], "default": { "nextState": "WaitForCompletion" } }, { "name":"JobSucceeded", "type":"OPERATION", "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "reportJobSuceeded", "parameters": { "name": "$.jobuid" } } } ], "end": { "kind": "DEFAULT" } }, { "name":"JobFailed", "type":"OPERATION", "actionMode":"SEQUENTIAL", "actions":[ { "functionRef": { "refName": "reportJobFailed", "parameters": { "name": "$.jobuid" } } } ], "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: jobmonitoring version: '1.0' name: Job Monitoring description: Monitor finished execution of a submitted job functions: - name: submitJob resource: submitJobResource - name: checkJobStatus resource: checkJobStatusResource - name: reportJobSuceeded resource: reportJobSuceededResource - name: reportJobFailed resource: reportJobFailedResource states: - name: SubmitJob type: OPERATION start: kind: DEFAULT actionMode: SEQUENTIAL actions: - functionRef: refName: submitJob parameters: name: "$.job.name" actionDataFilter: dataResultsPath: "$.jobuid" onError: - expression: language: spel body: "$.exception != null" errorDataFilter: dataOutputPath: "$.exception" transition: nextState: SubmitError stateDataFilter: dataOutputPath: "$.jobuid" transition: nextState: WaitForCompletion - name: SubmitError type: SUBFLOW workflowId: handleJobSubmissionErrorWorkflow end: kind: DEFAULT - name: WaitForCompletion type: DELAY timeDelay: PT5S transition: nextState: GetJobStatus - name: GetJobStatus type: OPERATION actionMode: SEQUENTIAL actions: - functionRef: refName: checkJobStatus parameters: name: "$.jobuid" actionDataFilter: dataResultsPath: "$.jobstatus" stateDataFilter: dataOutputPath: "$.jobstatus" transition: nextState: DetermineCompletion - name: DetermineCompletion type: SWITCH conditions: - path: "$.jobstatus" value: SUCCEEDED operator: Equals transition: nextState: JobSucceeded - path: "$.jobstatus" value: FAILED operator: Equals transition: nextState: JobFailed default: nextState: WaitForCompletion - name: JobSucceeded type: OPERATION actionMode: SEQUENTIAL actions: - functionRef: refName: reportJobSuceeded parameters: name: "$.jobuid" end: kind: DEFAULT - name: JobFailed type: OPERATION actionMode: SEQUENTIAL actions: - functionRef: refName: reportJobFailed parameters: name: "$.jobuid" end: kind: DEFAULT ```
#### Workflow Diagram

Job Monitoring Example

### Send CloudEvent On Workfow Completion Example #### Description This example shows how we can produce a CloudEvent on completion of a workflow. Let's say we have the following workflow data: ```json { "orders": [{ "id": "123", "item": "laptop", "quantity": "10" }, { "id": "456", "item": "desktop", "quantity": "4" }] } ``` Our workflow in this example uses a ForEach state to provision the orders in parallel. The "provisionOrder" function used is assumed to have the following results: ```json { "provisionedOrders": [ { "id": "123", "outcome": "SUCCESS" } ] } ``` After orders have been provisioned the ForEach states defines the end property which stops workflow execution. It defines its end definition to be of type "EVENT" in which case a CloudEvent will be produced which can be consumed by other orchestration workflows or other interested consumers. Note that we define the event to be produced in the workflows "events" property. The data attached to the event contains the information on provisioned orders by this workflow. So the produced CloudEvent upon completion of the workflow could look like: ```json { "specversion" : "1.0", "type" : "provisionCompleteType", "datacontenttype" : "application/json", ... "data": { "provisionedOrders": [ { "id": "123", "outcome": "SUCCESS" }, { "id": "456", "outcome": "FAILURE" } ] } } ``` #### Workflow Definition
JSON YAML
```json { "id": "sendcloudeventonprovision", "version": "1.0", "name": "Send CloudEvent on provision completion", "events": [ { "name": "provisioningCompleteEvent", "type": "provisionCompleteType", "source": "provisionCompleteSource" } ], "functions": [ { "name": "provisionOrderFunction", "resource": "functionResourse" } ], "states": [ { "name": "ProvisionOrdersState", "type": "FOREACH", "start": { "kind": "DEFAULT" }, "inputCollection": "$.orders", "inputParameter": "$.singleorder", "outputCollection": "$.results", "states": [ { "name": "DoProvision", "type": "OPERATION", "start": { "kind": "DEFAULT" }, "actionMode": "SEQUENTIAL", "actions": [ { "functionRef": { "refName": "provisionOrderFunction", "parameters": { "order": "$.order" } } } ], "end": { "kind": "DEFAULT" } } ], "stateDataFilter": { "dataOutputPath": "$.provisionedOrders" }, "end": { "kind": "EVENT", "produceEvent": { "nameRef": "provisioningCompleteEvent", "data": "$.provisionedOrders" } } } ] } ``` ```yaml id: sendcloudeventonprovision version: '1.0' name: Send CloudEvent on provision completion events: - name: provisioningCompleteEvent type: provisionCompleteType source: provisionCompleteSource functions: - name: provisionOrderFunction resource: functionResourse states: - name: ProvisionOrdersState type: FOREACH start: kind: DEFAULT inputCollection: "$.orders" inputParameter: "$.singleorder" outputCollection: "$.results" states: - name: DoProvision type: OPERATION start: kind: DEFAULT actionMode: SEQUENTIAL actions: - functionRef: refName: provisionOrderFunction parameters: order: "$.order" end: kind: DEFAULT stateDataFilter: dataOutputPath: "$.provisionedOrders" end: kind: EVENT produceEvent: nameRef: provisioningCompleteEvent data: "$.provisionedOrders" ```
#### Workflow Diagram

Send CloudEvent on Workflow Completion Example

### Monitor Patient Vital Signs Example #### Description In this example a hospital patient is monitored by a Vial Sign Monitoring system. This device can produce three different Cloud Events, namely "High Body Temperature", "High Blood Pressure", and "High Respiration Rate". Our workflow which needs to take proper actions depending on the event the Vital Sign Monitor produces needs to start if any of these events occur. For each of these events a new instance of the workflow is started. Since the hospital may include many patients that are being monitored it is assumed that all events include a patientId context attribute in the event message. We can use the value of this context attribute to associate the incoming events with the same patient as well as use the patient id to pass as parameter to the functions called by event activities. Here is an example of such event: ```json { "specversion" : "1.0", "type" : "org.monitor.highBodyTemp", "source" : "monitoringSource", "subject" : "BodyTemperatureReading", "id" : "A234-1234-1234", "time" : "2020-01-05T17:31:00Z", "patientId" : "PID-12345", "data" : { "value": "98.6F" } } ``` As you can see the "patientId" context attribute of the event includes our correlation key which is the unique patient id. If we set it to be the correlation key in our events definition, all events that are considered must have the matching patient id. #### Workflow Definition
JSON YAML
```json { "id": "patientVitalsWorkflow", "name": "Monitor Patient Vitals", "version": "1.0", "events": [ { "name": "HighBodyTemperature", "type": "org.monitor.highBodyTemp", "source": "monitoringSource", "correlationToken": "patientId" }, { "name": "HighBloodPressure", "type": "org.monitor.highBloodPressure", "source": "monitoringSource", "correlationToken": "patientId" }, { "name": "HighRespirationRate", "type": "org.monitor.highRespirationRate", "source": "monitoringSource", "correlationToken": "patientId" } ], "functions": [ { "name": "callPulmonologist", "type": "function", "resource": "callPulmonologistResource" }, { "name": "sendTylenolOrder", "type": "function", "resource": "sendTylenolOrderFunction" }, { "name": "callNurse", "type": "function", "resource": "callNurseResource" } ], "states": [ { "name": "MonitorVitals", "type": "EVENT", "start": { "kind": "DEFAULT" }, "exclusive": true, "eventsActions": [{ "eventRefs": ["HighBodyTemperature"], "actions": [{ "functionRef": { "refName": "sendTylenolOrder", "parameters": { "patientid": "$.patientId" } } }] }, { "eventRefs": ["HighBloodPressure"], "actions": [{ "functionRef": { "refName": "callNurse", "parameters": { "patientid": "$.patientId" } } }] }, { "eventRefs": ["HighRespirationRate"], "actions": [{ "functionRef": { "refName": "callPulmonologist", "parameters": { "patientid": "$.patientId" } } }] } ], "end": { "kind": "TERMINATE" } }] } ``` ```yaml id: patientVitalsWorkflow name: Monitor Patient Vitals version: '1.0' events: - name: HighBodyTemperature type: org.monitor.highBodyTemp source: monitoringSource correlationToken: patientId - name: HighBloodPressure type: org.monitor.highBloodPressure source: monitoringSource correlationToken: patientId - name: HighRespirationRate type: org.monitor.highRespirationRate source: monitoringSource correlationToken: patientId functions: - name: callPulmonologist type: function resource: callPulmonologistResource - name: sendTylenolOrder type: function resource: sendTylenolOrderFunction - name: callNurse type: function resource: callNurseResource states: - name: MonitorVitals type: EVENT start: kind: DEFAULT exclusive: true eventsActions: - eventRefs: - HighBodyTemperature actions: - functionRef: refName: sendTylenolOrder parameters: patientid: "$.patientId" - eventRefs: - HighBloodPressure actions: - functionRef: refName: callNurse parameters: patientid: "$.patientId" - eventRefs: - HighRespirationRate actions: - functionRef: refName: callPulmonologist parameters: patientid: "$.patientId" end: kind: TERMINATE ```
#### Workflow Diagram

Monitor Patient Vital Signs Example

### Finalize College Application Example #### Description In this example our workflow is instantiated when all requirements of a college application are completed. These requirements include a student submitting an application, the college receiving the students SAT scores, as well as a student recommendation letter from a former teacher. We assume three Cloud Events "ApplicationSubmitted", "SATScoresReceived" and "RecommendationLetterReceived". Each include the applicant id in their "applicantId" context attribute, so we can use it to associate these events with an individual applicant. Our workflow is instantiated and performs the actions to finalize the college application for a student only when all three of these events happened (in no particular order). #### Workflow Definition
JSON YAML
```json { "id": "finalizeCollegeApplication", "name": "Finalize College Application", "version": "1.0", "events": [ { "name": "ApplicationSubmitted", "type": "org.application.submitted", "source": "applicationsource", "correlationToken": "applicantId" }, { "name": "SATScoresReceived", "type": "org.application.satscores", "source": "applicationsource", "correlationToken": "applicantId" }, { "name": "RecommendationLetterReceived", "type": "org.application.recommendationLetter", "source": "applicationsource", "correlationToken": "applicantId" } ], "functions": [ { "name": "finalizeApplicationFunction", "type": "function", "resource": "finalizeApplicationResource" } ], "states": [ { "name": "FinalizeApplication", "type": "EVENT", "start": { "kind": "DEFAULT" }, "exclusive": false, "eventsActions": [ { "eventRefs": [ "ApplicationSubmitted", "SATScoresReceived", "RecommendationLetterReceived" ], "actions": [ { "functionRef": { "refName": "finalizeApplicationFunction", "parameters": { "student": "$.applicantId" } } } ] } ], "end": { "kind": "TERMINATE" } } ] } ``` ```yaml id: finalizeCollegeApplication name: Finalize College Application version: '1.0' events: - name: ApplicationSubmitted type: org.application.submitted source: applicationsource correlationToken: applicantId - name: SATScoresReceived type: org.application.satscores source: applicationsource correlationToken: applicantId - name: RecommendationLetterReceived type: org.application.recommendationLetter source: applicationsource correlationToken: applicantId functions: - name: finalizeApplicationFunction type: function resource: finalizeApplicationResource states: - name: FinalizeApplication type: EVENT start: kind: DEFAULT exclusive: false eventsActions: - eventRefs: - ApplicationSubmitted - SATScoresReceived - RecommendationLetterReceived actions: - functionRef: refName: finalizeApplicationFunction parameters: student: "$.applicantId" end: kind: TERMINATE ```
#### Workflow Diagram

Finalize College Application Example

### Perform Customer Credit Check Example #### Description In this example our serverless workflow needs to integrate with an external microservice to perform a credit check. We assume that this external microservice notifies a human actor which has to make the approval decision based on customer information. Once this decision is made the service emits a CloudEvent which includes the decision information as part of its payload. The workflow waits for this callback event and then triggers workflow transitions based on the credit check decision results. The workflow data input is assumed to be: ```json { "customer": { "id": "customer123", "name": "John Doe", "SSN": 123456, "yearlyIncome": 50000, "address": "123 MyLane, MyCity, MyCountry", "employer": "MyCompany" } } ``` The callback event that our workflow will wait on is assumed to have the following formats. For approved credit check, for example: ```json { "specversion" : "1.0", "type" : "creditCheckCompleteType", "datacontenttype" : "application/json", ... "data": { "creditCheck": [ { "id": "customer123", "score": 700, "decision": "Approved", "reason": "Good credit score" } ] } } ``` And for denied credit check, for example: ```json { "specversion" : "1.0", "type" : "creditCheckCompleteType", "datacontenttype" : "application/json", ... "data": { "creditCheck": [ { "id": "customer123", "score": 580, "decision": "Denied", "reason": "Low credit score. Recent late payments" } ] } } ``` #### Workflow Definition
JSON YAML
```json { "id": "customercreditcheck", "version": "1.0", "name": "Customer Credit Check Workflow", "description": "Perform Customer Credit Check", "functions": [ { "name": "callCreditCheckMicroservice", "resource": "creditCheckResource", "type": "microservice" }, { "name": "sendRejectionEmailFunction", "resource": "rejectEmailResource" } ], "events": [ { "name": "CreditCheckCompletedEvent", "type": "creditCheckCompleteType", "source": "creditCheckSource", "correlationToken": "customerId" } ], "states": [ { "name": "CheckCredit", "type": "CALLBACK", "start": { "kind": "DEFAULT" }, "action": { "functionRef": { "refName": "callCreditCheckMicroservice", "parameters": { "customer": "$.customer" } } }, "eventRef": "CreditCheckCompletedEvent", "timeout": "PT15M", "transition": { "nextState": "EvaluateDecision" } }, { "name": "EvaluateDecision", "type": "SWITCH", "conditions": [ { "path": "$.creditCheck.decision", "value": "Approved", "operator": "Equals", "transition": { "nextState": "StartApplication" } }, { "path": "$.creditCheck.decision", "value": "Denied", "operator": "Equals", "transition": { "nextState": "RejectApplication" } } ], "default": { "nextState": "RejectApplication" } }, { "name": "StartApplication", "type": "SUBFLOW", "workflowId": "startApplicationWorkflowId", "end": { "kind": "DEFAULT" } }, { "name": "RejectApplication", "type": "OPERATION", "actionMode": "SEQUENTIAL", "actions": [ { "functionRef": { "refName": "sendRejectionEmailFunction", "parameters": { "applicant": "$.customer" } } } ], "end": { "kind": "DEFAULT" } } ] } ``` ```yaml id: customercreditcheck version: '1.0' name: Customer Credit Check Workflow description: Perform Customer Credit Check functions: - name: callCreditCheckMicroservice resource: creditCheckResource type: microservice - name: sendRejectionEmailFunction resource: rejectEmailResource events: - name: CreditCheckCompletedEvent type: creditCheckCompleteType source: creditCheckSource correlationToken: customerId states: - name: CheckCredit type: CALLBACK start: kind: DEFAULT action: functionRef: refName: callCreditCheckMicroservice parameters: customer: "$.customer" eventRef: CreditCheckCompletedEvent timeout: PT15M transition: nextState: EvaluateDecision - name: EvaluateDecision type: SWITCH conditions: - path: "$.creditCheck.decision" value: Approved operator: Equals transition: nextState: StartApplication - path: "$.creditCheck.decision" value: Denied operator: Equals transition: nextState: RejectApplication default: nextState: RejectApplication - name: StartApplication type: SUBFLOW workflowId: startApplicationWorkflowId end: kind: DEFAULT - name: RejectApplication type: OPERATION actionMode: SEQUENTIAL actions: - functionRef: refName: sendRejectionEmailFunction parameters: applicant: "$.customer" end: kind: DEFAULT ```
#### Workflow Diagram

Perform Customer Credit Check Example

### Handle Car Auction Bids Example #### Description In this example our serverless workflow needs to handle bits for an online car auction. The car auction has a specific start and end time. Bids are only allowed to be made during this time period. All bids before or after this time should not be considered. We assume that the car auction starts at 9am UTC on March 20th 2020 and ends at 3pm UTC on March 20th 2020. Bidding is done via an online application and bids are received as events are assumed to have the following format: ```json { "specversion" : "1.0", "type" : "carBidType", "datacontenttype" : "application/json", ... "data": { "bid": [ { "carid": "car123", "amount": 3000, "bidder": { "id": "xyz", "firstName": "John", "lastName": "Wayne", } } ] } } ``` #### Workflow Definition
JSON YAML
```json { "id": "handleCarAuctionBid", "version": "1.0", "name": "Car Auction Bidding Workflow", "description": "Store a single bid whole the car auction is active", "functions": [ { "name": "StoreBidFunction", "resource": "storeBidResource", "type": "function" } ], "events": [ { "name": "CarBidEvent", "type": "carBidMadeType", "source": "carBidEventSource" } ], "states": [ { "name": "StoreCarAuctionBid", "type": "EVENT", "start": { "kind": "SCHEDULED", "schedule": { "interval": "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z" } }, "exclusive": true, "eventsActions": [ { "eventRefs": ["CarBidEvent"], "actions": [{ "functionRef": { "refName": "StoreBidFunction", "parameters": { "bid": "$.bid" } } }] } ], "end": { "kind": "TERMINATE" } } ] } ``` ```yaml id: handleCarAuctionBid version: '1.0' name: Car Auction Bidding Workflow description: Store a single bid whole the car auction is active functions: - name: StoreBidFunction resource: storeBidResource type: function events: - name: CarBidEvent type: carBidMadeType source: carBidEventSource states: - name: StoreCarAuctionBid type: EVENT start: kind: SCHEDULED schedule: interval: 2020-03-20T09:00:00Z/2020-03-20T15:00:00Z exclusive: true eventsActions: - eventRefs: - CarBidEvent actions: - functionRef: refName: StoreBidFunction parameters: bid: "$.bid" end: kind: TERMINATE ```
#### Workflow Diagram

Handle Car Auction Bid Example