Parallelism in SonataFlow

This document describes how you can run parallel tasks in SonataFlow.

The testing procedure described in this document is based on the serverless-workflow-service-calls-quarkus example application in GitHub repository.

SonataFlow serializes the execution of parallel tasks. Therefore, the word "parallel" does not indicate simultaneous execution, but it means that there is no logical dependency between the execution of branches. An inactive branch can start or resume the execution of a task without waiting for an active branch to be completed, in case the latter suspends the execution (for example, wait for an event reception).

The serverless-workflow-service-calls-quarkus example application is a workflow that concatenates three strings and returns a result. The concatenation in the example application is done in parallel, which includes one branch per three strings.

Creating a parallel workflow

You can create a workflow, which performs a series of parallel tasks.

Prerequisites
Procedure
  1. Create a workflow file named as parallel.sw.json under the src/main/resources/ directory.

  2. Add the following content to the parallel.sw.json file:

    Example content for parallel.sw.json file
    {
      "id": "parallel",
      "version": "1.0",
      "specVersion": "0.8",
      "name": "Welcome to the Parallel dimension",
      "description": "Testing parallelism",
      "start": "Parallel",
      "functions": [
        {
          "name": "concatA",
          "type": "expression",
          "operation": ".result|=.+\"A\"" (1)
        },
        {
          "name": "concatB",
          "type": "expression",
          "operation": ".result|=.+\"B\"" (2)
        },
        {
          "name": "concatC",
          "type": "expression",
          "operation": ".result|=.+\"C\"" (3)
        }
      ],
      "states": [
        {
          "name": "Parallel",
          "type": "parallel", (4)
          "branches": [ (5)
            {
              "name": "branchA",
              "actions": [
                {
                  "functionRef": "concatA" (6)
                }
              ]
            },
            {
              "name": "branchB",
              "actions": [
                {
                  "functionRef": "concatB" (7)
                }
              ]
            },
            {
              "name": "branchC",
              "actions": [
                {
                  "functionRef": "concatC" (8)
                }
              ]
            }
          ],
          "completionType": "allOf", (9)
          "end": {
            "terminate": true
          }
        }
      ]
    }
    1 Function that concatenates the string A.
    2 Function that concatenates the string B.
    3 Function that concatenates the string C.
    4 Defines the type of the state as parallel.
    5 Defines the branches that run in parallel.
    6 Defines the function that runs in branchA.
    7 Defines the function that runs in branchB.
    8 Defines the function that runs in branchC.
    9 Defines the completion type of the parallel state as allOf. This means that the parallel state is completed when all the branches are completed.

Running a parallel workflow

After you create a workflow that performs a series of parallel tasks, you can run the workflow.

Prerequisites
  • A parallel workflow is created.

    For more information, see Creating a parallel workflow.

  • The workflow application is up and running.

    You can start the workflow application in development mode by using the following command:

    mvn quarkus:dev
Procedure
  1. To run the created parallel workflow, send a request to the /parallel endpoint as shown in the following example request:

    Example request
    curl -X 'POST' \
      'http://localhost:8080/parallel' \
      -H 'accept: */*' \
      -H 'Content-Type: application/json' \
      -d '{}'
    Example response
    {"id":"358f97ba-f0f9-4f25-86cc-4b35e85c2406","workflowdata":{"result":"ABC"}}

    The "result":"ABC" in the previous example response might be different in each request since the branches are running in parallel and the execution order of the branches is unpredictable.

    Note that the parallel workflow data shows the concatenated string as result.

Running some branches in parallel workflow

You can define the "completionType": "atLeast" to run only some branches in parallel workflow, instead of defining "completionType": "allOf". When you define "completionType": "atLeast", you also need to define the minimum number of branches that you want to run by defining the "numCompleted": property.

Prerequisites
Procedure
  1. Change the completionType property to "atLeast" and add the "numCompleted": 2 property to the parallel state.

    Example parallel workflow
    {
      "id": "parallel",
      "version": "1.0",
      "specVersion": "0.8",
      "name": "Welcome to the Parallel dimension",
      "description": "Testing parallelism",
      "start": "Parallel",
      "functions": [
        {
          "name": "concatA",
          "type": "expression",
          "operation": ".result|=.+\"A\""
        },
        {
          "name": "concatB",
          "type": "expression",
          "operation": ".result|=.+\"B\""
        },
        {
          "name": "concatC",
          "type": "expression",
          "operation": ".result|=.+\"C\""
        }
      ],
      "states": [
        {
          "name": "Parallel",
          "type": "parallel",
          "branches": [
            {
              "name": "branchA",
              "actions": [
                {
                  "functionRef": "concatA"
                }
              ]
            },
            {
              "name": "branchB",
              "actions": [
                {
                  "functionRef": "concatB"
                }
              ]
            },
            {
              "name": "branchC",
              "actions": [
                {
                  "functionRef": "concatC"
                }
              ]
            }
          ],
          "completionType": "atLeast", (1)
          "numCompleted": "2", (2)
          "end": {
            "terminate": true
          }
        }
      ]
    }
    1 Defines the completion type of the parallel state as atLeast.
    2 Defines the minimum number of branches that you want to run. This means that the parallel state is completed when at least two branches are completed.
  2. To run the created parallel workflow, send a request to the /parallel endpoint as shown in the following example:

    Example request
    curl -X 'POST' \
      'http://localhost:8080/parallel' \
      -H 'accept: */*' \
      -H 'Content-Type: application/json' \
      -d '{}'
    Example response
    {"id":"3da62df1-c4e7-48c9-a3e4-7f63872c92f4","workflowdata":{"result":"BC"}}

    The "result":"BC" in the response might be different in each request.

    The parallel workflow data shows the concatenated string as result, but in this case, the workflow concatenates only two letters.

Found an issue?

If you find an issue or any misleading information, please feel free to report it here. We really appreciate it!