- 26 Apr 2023
Parallel Branching on the Canvas
- Updated on 26 Apr 2023
After a task has been assigned a finish state, the workflow will proceed by following any transitions from that task that have a matching binding value. This can lead to a workflow having concurrent execution paths. For example, a task that has two outgoing success transitions will follow both if it executes successfully. This is known as parallel branching.
Control of a workflow becomes more complicated when parallel branching is introduced. It is recommended to avoid parallel branching whenever possible.
Prerequisite Reading and Concepts
An overview of how parallel branching affects the behavior of a workflow is discussed within this document. Before proceeding, take note of the following:
- This document uses foundational concepts introduced in How to Use Transitions and Task States on the Canvas.
- Some example workflows provided in this document contain tasks and transitions visually highlighted in solid gray. This visualization denotes a task or transition that will not be used upon workflow execution. This is for documentation purposes only - it is not seen in normal operation of the canvas.
Example of Parallel Branching
In the workflow example below, there are two inputs to the Evaluation (Eval) task. It is impossible to know which of these two tasks will complete first, which is an inherent problem in parallel branching. Furthermore, the concept of having a path is vitally relevant. A path is defined as a series of tasks that begins with the Start task and culminates with the End task. One task might be part of many paths, especially when parallel branching is utilized.
Figure 1: Parallel Branching
The information below gives further detail as to how task execution flows through a workflow with parallel branching.
Possible Outcomes for Multiple Inputs to a Task
When there are multiple incoming transitions to a task there are three possible outcomes: all inputs are received, one input is received, or none of the task inputs are received.
All Inputs Received
There is no "waiting" for the specific transition binding value to occur before a task executes; rather, a task will execute if all of its precursor tasks have executed and, in turn, have "chosen a path". Even if the chosen path is different from the one visually drawn on the canvas, as long as the previous task has executed or declared itself to never execute (see the Tasks that Never Run section below), then the workflow can proceed. Moreover, if all incoming transitions run, then the subsequent task will run (which in the example below means the incoming tasks succeeded).
Figure 2: Parallel Branching - All Transitions Successful
One Input Received
When at least one of the incoming transitions occur, and even if all the other transitions are no longer possible, the subsequent task will still run. Keep in mind that any task references that do not exist will evaluate as null. In the example below, this causes the Evaluation task to take the failure (red) transition path instead of the success (green) transition path.
It is important to recognize the potential for confusion this causes when designing workflows. In Figure 2, when the transition in the right path between Stub and Eval shows success (green), the designer might assume the only way the workflow advances is if that particular condition occurs. That is not the correct interpretation of how a workflow runs.
As shown in Figure 3, the Stub task chose a path at runtime which is shown in gray. This means the task run was completed, but since the result was not green (success), it has done as much as it can do. The left path that was chosen (i.e. the "green" path) and the Evaluation task is now free to execute. In this case, the Evaluation task is conditional and will evaluate any references to the right parallel path's Stub variables as null.
Figure 3: Parallel Branching - One Transition Successful
No Input Received
When neither of the incoming task succeeds, the subsequent task will never run. Furthermore, if this is the only task that leads to the End task, the job will fail.
Figure 4: Parallel Branching - No Transitions Successful
Tasks that Never Run
The scenario in the No Input Received section introduces the topic of a "task that never runs." This section provides additional information to explain the behavior.
If a task never runs, it will still notify the subsequent tasks to determine if they should run in the future, based on the logic for parallel branching. For example, if the workflow below was to run and the Stub task errors, it notifies all of its connected tasks of a different transition type (e.g., "success") that these transitions will never be taken. If the next task will never run (i.e., the first Query along the right parallel path), it notifies its subsequent task that it will never run (e.g., the second Query along the right parallel path). Then that task notifies its subsequent task that it will also never run (i.e., the Evaluation task). This continues until the End task or a task that has multiple inputs is reached. Due to this mode of operation, it becomes necessary that you give careful attention to any and all parallel paths to prevent a job from never completing (as illustrated below).
Figure 5: Parallel Branching with Unused Transitions
Furthermore, if there is a case in parallel branching where it is one of two incoming tasks for a subsequent task and the other task succeeds, it will then run the subsequent task, even if it may not have all the necessary data to run successfully. The workflow below is an example of this (Figure 6). If the Stub task fails, it notifies the subsequent task (Query) that its transition will never run and that Query task in turn notifies the second Query task that its transition will never run. The Evaluation task will be notified that the right path will never run and, therefore, it is free to look to its other inputs to see if it can run. At this point, the Evaluation task just needs the left path to run and once it does, it sets the references for the unexecuted Query task on the right path to null and performs the evaluation.
Figure 6: Parallel Branching with Unused Transitions in Runtime
Revert Transitions in Parallel Branching
Determining the order of execution in a path becomes more complex when a workflow contains both a revert transition and parallel branching. In these cases, when designing a workflow, you must separate how the workflow will look visually so as not to confuse how the workflow will run (flow) through its paths. When a revert transition occurs, all tasks on the path from the revert's destination task to the "End" task will be reset and executed again (even if they had already executed due to traversal of a different parallel path).
Use of a revert within a parallel branch can cause all subsequent workflow tasks to run multiple times (1 + the number of reverts). This is expected behavior, so remember to plan your workflows accordingly.
The following scenarios illustrate how reverts and parallel paths operate.
In the workflow below, a task has two paths that lead to an Evaluation task (i.e., a "shared" Evaluation task). The right path contains its own Evaluation task, which in this scenario will fail the first time, then the job variable will be set to a value that is meant to cause the second run of the Evaluation task to succeed. However, the transition from that variable is a revert back to the "Evaluation" task, so it is only after the revert transition that the second execution of that Evaluation task will yield a success.
Figure 7: Parallel Branching with Revert Transitions
Due to the first execution of the Evaluation task, the right path fails and then goes to a task which has a revert transition. The first Evaluation task will notify the "shared" Evaluation task that the path between them will never run.
While this is occurring, the left path executes and reaches the "shared" Evaluation task (the one where both the left and right paths meet) and will run for the first time. Since both of the previous tasks to the shared Evaluation task have chosen a path, the task will run but in this case fail because it does not have the correct data (the "shared" Evaluation task is expecting data from both paths). Consequently, a "failure" path to the Query task is executed, as illustrated below (Figure 8).
Figure 8: Parallel Branching with Revert Transitions in Runtime Before a Revert Transition
Lastly, when the right path reaches the revert transition, it will reset all tasks subsequent to the first Evaluation task along its path and start executing again. This means the second Evaluation task will run a second time. In order to avoid scenarios like this, it is best to find an alternative to using revert within parallel branching, such as converting the workflow to run sequentially or using a child job to handle the revert logic.
Figure 9: Parallel Branching with Revert Transitions in Runtime After a Revert Transition
Revert Transitions in Parallel Branching with Child Jobs
Another scenario involving revert transitions involves child jobs used within parallel branching. When reverting over a workflow which uses parallel paths, this may also revert over a running child job task. This will not stop the previously running child job from executing but instead launch a second child job.
Use of a revert within a parallel branch can cause multiple instances of the same child job to run simultaneously. Itential recommends that you avoid this when possible.
The following scenario illustrates how running child jobs behave when reverted over in a parallel path.
In the below workflow (Figure 10), the Stub task has parallel branches to both a ViewData manual task and a childJob task. Assuming the manual task is worked before the child job finishes, when the manual task is worked the job will revert to the Stub task, which will succeed and then again execute the Child Job task. However, this will not cancel or replace the initial child job, but instead execute a brand new child job. The first child job will still continue running until it is completed, just like any other automatic task. Otherwise, there is no way for the parent job to understand the state of the first child job when it was reverted over. If these previous child jobs are no longer needed, it should be safe to cancel these child jobs manually.
It should be noted that this behavior also works the same as when manually reverting over a paused child job.
Figure 10: Parallel Branching with Revert Transitions over a Child Job