# Serverless Workflow Specification - Version 0.8 ## Table of Contents - [Abstract](#abstract) - [Status of this document](#status-of-this-document) - [Overview](#overview) * [Why we need a specification?](#why-we-need-a-specification) * [Focus on standards](#focus-on-standards) - [Project Components](#project-components) - [Specification Details](#specification-details) * [Core Concepts](#core-concepts) * [Workflow Definition](#workflow-definition) * [Workflow Instance](#workflow-instance) * [Workflow Model](#workflow-model) * [Workflow Data](#workflow-data) + [Workflow Data Input](#workflow-data-input) + [Information Passing Between States](#information-passing-between-states) + [Workflow data output](#workflow-data-output) + [State data filters](#state-data-filters) + [Action data filters](#action-data-filters) + [Event data filters](#event-data-filters) + [Using multiple data filters](#using-multiple-data-filters) + [Data Merging](#data-merging) * [Workflow Functions](#workflow-functions) + [Using Functions for RESTful Service Invocations](#using-functions-for-restful-service-invocations) + [Using Functions for Async API Service Invocations](#using-functions-for-async-api-service-invocations) + [Using Functions for RPC Service Invocations](#using-functions-for-rpc-service-invocations) + [Using Functions for GraphQL Service Invocations](#using-functions-for-graphql-service-invocations) - [Invoking a GraphQL `Query`](#invoking-a-graphql-query) - [Invoking a GraphQL `Mutation`](#invoking-a-graphql-mutation) + [Using Functions for OData Service Invocations](#using-functions-for-odata-service-invocations) - [Creating an OData Function Definition](#creating-an-odata-function-definition) - [Invoking an OData Function Definition](#invoking-an-odata-function-definition) + [Using Functions for Expression Evaluation](#using-functions-for-expression-evaluation) + [Defining custom function types](#defining-custom-function-types) * [Workflow Expressions](#workflow-expressions) * [Workflow Definition Structure](#workflow-definition-structure) + [Workflow States](#workflow-states) - [Event State](#event-state) - [Operation State](#operation-state) - [Switch State](#switch-state) - [Sleep State](#sleep-state) - [Parallel State](#parallel-state) - [Inject State](#inject-state) - [ForEach State](#foreach-state) - [Callback State](#callback-state) + [Related State Definitions](#related-state-definitions) - [Function Definition](#function-definition) - [Event Definition](#event-definition) - [Auth Definition](#auth-definition) - [Basic Properties Definition](#basic-properties-definition) - [Bearer Properties Definition](#bearer-properties-definition) - [OAuth2 Properties Definition](#oauth2-properties-definition) - [Correlation Definition](#correlation-definition) - [OnEvents Definition](#onevents-definition) - [Action Definition](#action-definition) - [Subflow Action](#subflow-action) - [FunctionRef Definition](#functionref-definition) - [EventRef Definition](#eventref-definition) - [SubFlowRef Definition](#subflowref-definition) - [Error Definition](#error-definition) - [Retry Definition](#retry-definition) - [Transition Definition](#transition-definition) - [Switch State Data Conditions](#switch-state-data-conditions) - [Switch State Event Conditions](#switch-state-event-conditions) - [Parallel State Branch](#parallel-state-branch) - [Parallel State Handling Exceptions](#parallel-state-handling-exceptions) - [Start Definition](#start-definition) - [Schedule Definition](#schedule-definition) - [Cron Definition](#cron-definition) - [End Definition](#end-definition) - [ProducedEvent Definition](#producedevent-definition) - [Transitions](#transitions) - [Additional Properties](#additional-properties) * [Workflow Error Handling](#workflow-error-handling) + [Defining Errors](#defining-errors) * [Action retries](#action-retries) + [Retry actions on known errors](#retry-actions-on-known-errors) + [Automatic retries on known and unknown errors](#automatic-retries-on-known-and-unknown-errors) * [Workflow Timeouts](#workflow-timeouts) + [Workflow Timeout Definition](#workflow-timeout-definition) - [WorkflowExecTimeout Definition](#workflowexectimeout-definition) + [States Timeout Definition](#states-timeout-definition) + [Branch Timeout Definition](#branch-timeout-definition) + [Event Timeout Definition](#event-timeout-definition) * [Workflow Compensation](#workflow-compensation) + [Defining Compensation](#defining-compensation) + [Triggering Compensation](#triggering-compensation) + [Compensation Execution Details](#compensation-execution-details) + [Compensation and Active States](#compensation-and-active-states) + [Unrecoverable errors during compensation](#unrecoverable-errors-during-compensation) * [Continuing as a new Execution](#continuing-as-a-new-execution) + [ContinueAs in sub workflows](#continueas-in-sub-workflows) * [Workflow Versioning](#workflow-versioning) * [Workflow Constants](#workflow-constants) * [Workflow Secrets](#workflow-secrets) * [Workflow Metadata](#workflow-metadata) - [Extensions](#extensions) - [Use Cases](#use-cases) - [Examples](#examples) - [Comparison to other workflow languages](#comparison-to-other-workflow-languages) - [References](#references) - [License](#license) ## Abstract The Serverless Workflow project defines a vendor-neutral and declarative workflow language, targeting the Serverless computing technology domain. ## Status of this document This document represents the current state of the specification. It includes all features so far released as well as all features planned to be added in the next release. You can find all specification releases [here](https://github.com/serverlessworkflow/specification/releases). You can find the specification roadmap [here](roadmap/README.md). ## Overview Workflows allow us to capture and organize business requirements in a unified manner. They can bridge the gap between how we express and model business logic. A key component of workflows is the domain-specific language (DSL) we use to model our business logic and solutions. Selecting the appropriate workflow language for our business and technology domains is a very important decision to be considered. Serverless Workflow focuses on defining a **vendor-neutral**, **platform-independent**, and **declarative** workflow language that targets the serverless computing technology domain. It can be used to significantly bridge the gap between your unique business domain and the target technology domain. ### Why we need a specification? The lack of a common way to define and model workflows means that we must constantly re-learn how to write them. This also limits the potential for common libraries, tooling and infrastructure to aid workflow modeling and execution across different platforms. Portability as well as productivity that can be achieved from workflow orchestration is hindered overall. Serverless Workflow addresses the need for a community-driven, vendor-neutral and a platform-independent workflow language specification that targets the serverless computing technology domain. Having and using a specification-based workflow language allows us to model our workflows once and deploy them onto many different container/cloud platforms, expecting the same execution results.
| JSON | YAML |
|---|---|
| ```json { "stateDataFilter": { "input": "${ .orders }", "output": "${ .provisionedOrders }" } } ``` | ```yaml stateDataFilter: input: "${ .orders }" output: "${ .provisionedOrders }" ``` |
| JSON | YAML |
|---|---|
| ```json { "actionDataFilter": { "fromStateData": "${ .language }", "results": "${ .results.greeting }", "toStateData": "${ .finalgreeting }" } } ``` | ```yaml actionDataFilter: fromStateData: "${ .language }" results: "${ .results.greeting }" toStateData: "${ .finalgreeting }" ``` |
| JSON | YAML |
|---|---|
| ```json { "eventDataFilter": { "data": "${ .data.results }" } } ``` | ```yaml eventDataFilter: data: "${ .data.results }" ``` |
| JSON | YAML |
|---|---|
| ```json { "id": "sampleWorkflow", "version": "1.0", "specVersion": "0.8", "name": "Sample Workflow", "description": "Sample Workflow", "start": "MyStartingState", "states": [], "functions": [], "events": [], "errors": [], "retries":[] } ``` | ```yaml id: sampleWorkflow version: '1.0' specVersion: '0.8' name: Sample Workflow description: Sample Workflow start: MyStartingState states: [] functions: [] events: [] errors: [] retries: [] ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "MonitorVitals", "type": "event", "exclusive": true, "onEvents": [{ "eventRefs": ["HighBodyTemperature"], "actions": [{ "functionRef": { "refName": "sendTylenolOrder", "arguments": { "patientid": "${ .patientId }" } } }] }, { "eventRefs": ["HighBloodPressure"], "actions": [{ "functionRef": { "refName": "callNurse", "arguments": { "patientid": "${ .patientId }" } } }] }, { "eventRefs": ["HighRespirationRate"], "actions": [{ "functionRef": { "refName": "callPulmonologist", "arguments": { "patientid": "${ .patientId }" } } }] } ], "end": { "terminate": true } } ``` | ```yaml name: MonitorVitals type: event exclusive: true onEvents: - eventRefs: - HighBodyTemperature actions: - functionRef: refName: sendTylenolOrder arguments: patientid: "${ .patientId }" - eventRefs: - HighBloodPressure actions: - functionRef: refName: callNurse arguments: patientid: "${ .patientId }" - eventRefs: - HighRespirationRate actions: - functionRef: refName: callPulmonologist arguments: patientid: "${ .patientId }" end: terminate: true ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "RejectApplication", "type": "operation", "actionMode": "sequential", "actions": [ { "functionRef": { "refName": "sendRejectionEmailFunction", "arguments": { "customer": "${ .customer }" } } } ], "end": true } ``` | ```yaml name: RejectApplication type: operation actionMode: sequential actions: - functionRef: refName: sendRejectionEmailFunction arguments: customer: "${ .customer }" end: true ``` |
| JSON | YAML |
|---|---|
| ```json { "name":"CheckVisaStatus", "type":"switch", "eventConditions": [ { "eventRef": "visaApprovedEvent", "transition": "HandleApprovedVisa" }, { "eventRef": "visaRejectedEvent", "transition": "HandleRejectedVisa" } ], "eventTimeout": "PT1H", "defaultCondition": { "transition": "HandleNoVisaDecision" } } ``` | ```yaml name: CheckVisaStatus type: switch eventConditions: - eventRef: visaApprovedEvent transition: HandleApprovedVisa - eventRef: visaRejectedEvent transition: HandleRejectedVisa eventTimeout: PT1H defaultCondition: transition: HandleNoVisaDecision ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "SleepFiveSeconds", "type": "sleep", "duration": "PT5S", "transition": "GetJobStatus" } ``` | ```yaml name: SleepFiveSeconds type: sleep duration: PT5S transition: GetJobStatus ``` |
| JSON | YAML |
|---|---|
| ```json { "name":"ParallelExec", "type":"parallel", "completionType": "allOf", "branches": [ { "name": "Branch1", "actions": [ { "functionRef": { "refName": "functionNameOne", "arguments": { "order": "${ .someParam }" } } } ] }, { "name": "Branch2", "actions": [ { "functionRef": { "refName": "functionNameTwo", "arguments": { "order": "${ .someParam }" } } } ] } ], "end": true } ``` | ```yaml name: ParallelExec type: parallel completionType: allOf branches: - name: Branch1 actions: - functionRef: refName: functionNameOne arguments: order: "${ .someParam }" - name: Branch2 actions: - functionRef: refName: functionNameTwo arguments: order: "${ .someParam }" end: true ``` |
| JSON | YAML |
|---|---|
| ```json { "name":"Hello", "type":"inject", "data": { "result": "Hello" }, "transition": "World" } ``` | ```yaml name: Hello type: inject data: result: Hello transition: World ``` |
| JSON | YAML |
|---|---|
| ```json { "name":"SimpleInjectState", "type":"inject", "data": { "person": { "fname": "John", "lname": "Doe", "address": "1234 SomeStreet", "age": 40 } }, "transition": "GreetPersonState" } ``` | ```yaml name: SimpleInjectState type: inject data: person: fname: John lname: Doe address: 1234 SomeStreet age: 40 transition: GreetPersonState ``` |
| JSON | YAML |
|---|---|
| ```json { "name":"SimpleInjectState", "type":"inject", "data": { "people": [ { "fname": "John", "lname": "Doe", "address": "1234 SomeStreet", "age": 40 }, { "fname": "Marry", "lname": "Allice", "address": "1234 SomeStreet", "age": 25 }, { "fname": "Kelly", "lname": "Mill", "address": "1234 SomeStreet", "age": 30 } ] }, "stateDataFilter": { "output": "${ {people: [.people[] | select(.age < 40)]} }" }, "transition": "GreetPersonState" } ``` | ```yaml name: SimpleInjectState type: inject data: people: - fname: John lname: Doe address: 1234 SomeStreet age: 40 - fname: Marry lname: Allice address: 1234 SomeStreet age: 25 - fname: Kelly lname: Mill address: 1234 SomeStreet age: 30 stateDataFilter: output: "${ {people: [.people[] | select(.age < 40)]} }" transition: GreetPersonState ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "ProvisionOrdersState", "type": "foreach", "inputCollection": "${ .orders }", "iterationParam": "singleorder", "outputCollection": "${ .provisionresults }", "actions": [ { "functionRef": { "refName": "provisionOrderFunction", "arguments": { "order": "${ .singleorder }" } } } ] } ``` | ```yaml name: ProvisionOrdersState type: foreach inputCollection: "${ .orders }" iterationParam: "singleorder" outputCollection: "${ .provisionresults }" actions: - functionRef: refName: provisionOrderFunction arguments: order: "${ .singleorder }" ``` |
| JSON | YAML |
|---|---|
| ```json { "id": "sendConfirmWorkflow", "name": "SendConfirmationForCompletedOrders", "version": "1.0", "specVersion": "0.8", "start": "SendConfirmState", "functions": [ { "name": "sendConfirmationFunction", "operation": "file://confirmationapi.json#sendOrderConfirmation" } ], "states": [ { "name":"SendConfirmState", "type":"foreach", "inputCollection": "${ [.orders[] | select(.completed == true)] }", "iterationParam": "completedorder", "outputCollection": "${ .confirmationresults }", "actions":[ { "functionRef": { "refName": "sendConfirmationFunction", "arguments": { "orderNumber": "${ .completedorder.orderNumber }", "email": "${ .completedorder.email }" } } }], "end": true }] } ``` | ```yaml id: sendConfirmWorkflow name: SendConfirmationForCompletedOrders version: '1.0' specVersion: '0.8' start: SendConfirmState functions: - name: sendConfirmationFunction operation: file://confirmationapi.json#sendOrderConfirmation states: - name: SendConfirmState type: foreach inputCollection: "${ [.orders[] | select(.completed == true)] }" iterationParam: completedorder outputCollection: "${ .confirmationresults }" actions: - functionRef: refName: sendConfirmationFunction arguments: orderNumber: "${ .completedorder.orderNumber }" email: "${ .completedorder.email }" end: true ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "CheckCredit", "type": "callback", "action": { "functionRef": { "refName": "callCreditCheckMicroservice", "arguments": { "customer": "${ .customer }" } } }, "eventRef": "CreditCheckCompletedEvent", "timeouts": { "stateExecTimeout": "PT15M" }, "transition": "EvaluateDecision" } ``` | ```yaml name: CheckCredit type: callback action: functionRef: refName: callCreditCheckMicroservice arguments: customer: "${ .customer }" eventRef: CreditCheckCompletedEvent timeouts: stateExecTimeout: PT15M transition: EvaluateDecision ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "HelloWorldFunction", "operation": "https://hellworldservice.api.com/api.json#helloWorld" } ``` | ```yaml name: HelloWorldFunction operation: https://hellworldservice.api.com/api.json#helloWorld ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "ApplicantInfo", "type": "org.application.info", "source": "applicationssource", "kind": "consumed", "correlation": [ { "contextAttributeName": "applicantId" } ] } ``` | ```yaml name: ApplicantInfo type: org.application.info source: applicationssource kind: consumed correlation: - contextAttributeName: applicantId ``` |
| JSON | YAML |
|---|---|
| ```json { "correlation": [ { "contextAttributeName": "patientId" }, { "contextAttributeName": "department", "contextAttributeValue" : "UrgentCare" } ] } ``` | ```yaml correlation: - contextAttributeName: patientId - contextAttributeName: department contextAttributeValue: UrgentCare ``` |
| JSON | YAML |
|---|---|
| ```json { "eventRefs": ["HighBodyTemperature"], "actions": [{ "functionRef": { "refName": "sendTylenolOrder", "arguments": { "patientid": "${ .patientId }" } } }] } ``` | ```yaml eventRefs: - HighBodyTemperature actions: - functionRef: refName: sendTylenolOrder arguments: patientid: "${ .patientId }" ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "Finalize Application Action", "functionRef": { "refName": "finalizeApplicationFunction", "arguments": { "applicantid": "${ .applicantId }" } } } ``` | ```yaml name: Finalize Application Action functionRef: refName: finalizeApplicationFunction arguments: applicantid: "${ .applicantId }" ``` |
| JSON | YAML |
|---|---|
| ```json { "refName": "finalizeApplicationFunction", "arguments": { "applicantid": "${ .applicantId }" } } ``` | ```yaml refName: finalizeApplicationFunction arguments: applicantid: "${ .applicantId }" ``` |
| JSON | YAML |
|---|---|
| ```json { "eventRef": { "triggerEventRef": "MakeVetAppointment", "data": "${ .patientInfo }", "resultEventRef": "VetAppointmentInfo" } } ``` | ```yaml eventRef: triggerEventRef: MakeVetAppointment data: "${ .patientInfo }" resultEventRef: VetAppointmentInfo ``` |
| JSON | YAML |
|---|---|
| ```json { "workflowId": "handleApprovedVisaWorkflowID", "version": "2.0" } ``` | ```yaml workflowId: handleApprovedVisaWorkflowID version: '2.0' ``` |
| JSON | YAML |
|---|---|
| ```json { "errorRef": "Item not in inventory", "transition": "IssueRefundToCustomer" } ``` | ```yaml errorRef: Item not in inventory transition: IssueRefundToCustomer ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "TimeoutRetryStrat", "delay": "PT2M", "maxAttempts": 3, "jitter": "PT0.001S" } ``` | ```yaml name: TimeoutRetryStrat delay: PT2M maxAttempts: 3 jitter: PT0.001S ``` |
| JSON | YAML |
|---|---|
| ```json { "produceEvents": [{ "eventRef": "produceResultEvent", "data": "${ .result.data }" }], "nextState": "EvalResultState" } ``` | ```yaml produceEvents: - eventRef: produceResultEvent data: "${ .result.data }" nextState: EvalResultState ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "Eighteen or older", "condition": "${ .applicant | .age >= 18 }", "transition": "StartApplication" } ``` | ```yaml name: Eighteen or older condition: "${ .applicant | .age >= 18 }" transition: StartApplication ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "Visa approved", "eventRef": "visaApprovedEvent", "transition": "HandleApprovedVisa" } ``` | ```yaml name: Visa approved eventRef: visaApprovedEvent transition: HandleApprovedVisa ``` |
| JSON | YAML |
|---|---|
| ```json { "name": "Branch1", "actions": [ { "functionRef": { "refName": "functionNameOne", "arguments": { "order": "${ .someParam }" } } }, { "functionRef": { "refName": "functionNameTwo", "arguments": { "order": "${ .someParamTwo }" } } } ] } ``` | ```yaml name: Branch1 actions: - functionRef: refName: functionNameOne arguments: order: "${ .someParam }" - functionRef: refName: functionNameTwo arguments: order: "${ .someParamTwo }" ``` |
| JSON | YAML |
|---|---|
| ```json { "stateName": "MyStartingstate", "schedule": "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z" } ``` | ```yaml stateName: MyStartingstate schedule: 2020-03-20T09:00:00Z/2020-03-20T15:00:00Z ``` |
| JSON | YAML |
|---|---|
| ```json { "cron": "0 0/15 * * * ?" } ``` | ```yaml cron: 0 0/15 * * * ? ``` |
| JSON | YAML |
|---|---|
| ```json { "expression": "0 15,30,45 * ? * *", "validUntil": "2021-11-05T08:15:30-05:00" } ``` | ```yaml expression: 0 15,30,45 * ? * * validUntil: '2021-11-05T08:15:30-05:00' ``` |
| JSON | YAML |
|---|---|
| ```json { "terminate": true, "produceEvents": [{ "eventRef": "provisioningCompleteEvent", "data": "${ .provisionedOrders }" }] } ``` | ```yaml terminate: true produceEvents: - eventRef: provisioningCompleteEvent data: "${ .provisionedOrders }" ``` |
| JSON | YAML |
|---|---|
| ```json { "eventRef": "provisioningCompleteEvent", "data": "${ .provisionedOrders }", "contextAttributes": [{ "buyerId": "${ .buyerId }" }] } ``` | ```yaml eventRef: provisioningCompleteEvent data: "${ .provisionedOrders }" contextAttributes: - buyerId: "${ .buyerId }" ``` |
| JSON | YAML |
|---|---|
| ```json { "errors": "file://documents/reusable/errors.json" } ``` | ```yaml errors: file://documents/reusable/errors.json ``` |
| JSON | YAML |
|---|---|
| ```json { "errors": [ { "name": "Service not found error", "code": "404", "description": "Server has not found anything matching the provided service endpoint information" } ] } ``` | ```yaml errors: - name: Service not found error code: '404' description: Server has not found anything matching the provided service endpoint information ``` |
| JSON | YAML |
|---|---|
| ```json { "retries": [ { "name": "FirstRetryStrategy", "delay": "PT1M", "maxAttempts": 5 }, { "name": "SecondRetryStrategy", "delay": "PT10M", "maxAttempts": 10 } ] } ``` | ```yaml retries: - name: FirstRetryStrategy delay: PT1M maxAttempts: 5 - name: SecondRetryStrategy delay: PT10M maxAttempts: 10 ``` |
| JSON | YAML |
|---|---|
| ```json { "actions": [ { "functionRef": "MyFirstFunction", "retryRef": "FirstRetryStrategy", "retryableErrors": ["SomeErrorOne", "SomeErrorTwo"] }, { "functionRef": "MySecondFunction", "retryRef": "SecondRetryStrategy", "retryableErrors": ["SomeErrorTwo", "SomeErrorThree"] }, { "functionRef": "MyThirdFunction" } ] } ``` | ```yaml actions: - functionRef: MyFirstFunction retryRef: FirstRetryStrategy nonRetryableErrors: - SomeErrorOne - SomeErrorTwo - functionRef: MySecondFunction retryRef: SecondRetryStrategy nonRetryableErrors: - SomeErrorTwo - SomeErrorThree - functionRef: MyThirdFunction ``` |
| JSON | YAML |
|---|---|
| ```json { "retries": [ { "name": "FirstRetryStrategy", "delay": "PT1M", "maxAttempts": 5 }, { "name": "SecondRetryStrategy", "delay": "PT10M", "maxAttempts": 10 }, { "name": "DoNotRetryStrategy", "maxAttempts": 1 } ] } ``` | ```yaml retries: - name: FirstRetryStrategy delay: PT1M maxAttempts: 5 - name: SecondRetryStrategy delay: PT10M maxAttempts: 10 - name: DoNotRetryStrategy maxAttempts: 1 ``` |
| JSON | YAML |
|---|---|
| ```json { "actions": [ { "functionRef": "MyFirstFunction", "retryRef": "FirstRetryStrategy", "nonRetryableErrors": ["SomeErrorOne", "SomeErrorTwo"] }, { "functionRef": "MySecondFunction", "retryRef": "SecondRetryStrategy", "nonRetryableErrors": ["SomeErrorTwo", "SomeErrorThree"] }, { "functionRef": "MyThirdFunction" }, { "functionRef": "MyFourthFunction", "retryRef": "DoNotRetryStrategy" } ] } ``` | ```yaml actions: - functionRef: MyFirstFunction retryRef: FirstRetryStrategy nonRetryableErrors: - SomeErrorOne - SomeErrorTwo - functionRef: MySecondFunction retryRef: SecondRetryStrategy nonRetryableErrors: - SomeErrorTwo - SomeErrorThree - functionRef: MyThirdFunction - functionRef: MyFourthFunction retryRef: DoNotRetryStrategy ``` |
| JSON | YAML |
|---|---|
| ```json { "duration": "PT2M", "runBefore": "createandsendreport" } ``` | ```yaml duration: PT2M runBefore: createandsendreport ``` |
| JSON | YAML |
|---|---|
| ```json { "states": [ { "name": "NewItemPurchase", "type": "event", "onEvents": [ { "eventRefs": [ "NewPurchase" ], "actions": [ { "functionRef": { "refName": "DebitCustomerFunction", "arguments": { "customerid": "${ .purchase.customerid }", "amount": "${ .purchase.amount }" } } }, { "functionRef": { "refName": "SendPurchaseConfirmationEmailFunction", "arguments": { "customerid": "${ .purchase.customerid }" } } } ] } ], "compensatedBy": "CancelPurchase", "transition": "SomeNextWorkflowState" }, { "name": "CancelPurchase", "type": "operation", "usedForCompensation": true, "actions": [ { "functionRef": { "refName": "CreditCustomerFunction", "arguments": { "customerid": "${ .purchase.customerid }", "amount": "${ .purchase.amount }" } } }, { "functionRef": { "refName": "SendPurchaseCancellationEmailFunction", "arguments": { "customerid": "${ .purchase.customerid }" } } } ] } ] } ``` | ```yaml states: - name: NewItemPurchase type: event onEvents: - eventRefs: - NewPurchase actions: - functionRef: refName: DebitCustomerFunction arguments: customerid: "${ .purchase.customerid }" amount: "${ .purchase.amount }" - functionRef: refName: SendPurchaseConfirmationEmailFunction arguments: customerid: "${ .purchase.customerid }" compensatedBy: CancelPurchase transition: SomeNextWorkflowState - name: CancelPurchase type: operation usedForCompensation: true actions: - functionRef: refName: CreditCustomerFunction arguments: customerid: "${ .purchase.customerid }" amount: "${ .purchase.amount }" - functionRef: refName: SendPurchaseCancellationEmailFunction arguments: customerid: "${ .purchase.customerid }" ``` |
| JSON | YAML |
|---|---|
| ```json { "transition": { "compensate": true, "nextState": "NextWorkflowState" } } ``` | ```yaml transition: compensate: true nextState: NextWorkflowState ``` |
| JSON | YAML |
|---|---|
| ```json { "end": { "compensate": true } } ``` | ```yaml end: compensate: true ``` |