Skip to Content
Evaluate Get Started Plugins Glossary

Managing Subprocesses

Coordinate parallel work across departments, services, or approval chains by creating child subprocesses through fork transitions. Without CheckAllSubprocessesCompleted and DeleteSubprocesses, every scheme that needs to wait for parallel branches or clean up active children would require custom code. These built-in actions handle subprocess lifecycle in conjunction with the scheme's fork and merge transitions.

How subprocesses work in Workflow Engine

A subprocess is a process instance that runs as a child of a parent process. Subprocesses are created through fork transitions on the scheme, not through the CreateProcess action:

  • Fork transitions (IsFork="true") with SubprocessInOutDefinition="Start" create child subprocesses that execute in parallel.
  • Merge transitions with SubprocessInOutDefinition="Finalize" bring subprocesses back to the parent.
  • CheckAllSubprocessesCompleted checks the process tree for active children.
  • DeleteSubprocesses deletes all child subprocesses.

CreateProcess is a separate action that creates independent process instances without a parent-child relationship. It is not tracked by CheckAllSubprocessesCompleted or DeleteSubprocesses.

Real-world scenario: employee onboarding

A company onboarding workflow assigns tasks across three departments when a new employee joins. The parent workflow forks into three parallel subprocesses - one for IT (provision laptop), one for HR (enrollment), and one for Facilities (desk assignment). Each subprocess runs independently. The parent waits until all three subprocesses complete before marking the employee as onboarded.

Workflow scheme

The parent scheme forks into three subprocess branches. Each branch (IT_Department, HR_Department, Facilities_Department) runs as a child process. When all three merge back, CheckAllSubprocessesCompleted allows the process to finalize.

Employee onboarding workflow scheme

Related capabilities: CheckAllSubprocessesCompleted condition, DeleteSubprocesses action, fork/merge transitions, CreateProcess action.

employee-onboarding.xml
<Process Name="EmployeeOnboarding" CanBeInlined="false">  <Designer />  <Commands>    <Command Name="CompleteIT" />    <Command Name="CompleteHR" />    <Command Name="CompleteFacilities" />  </Commands>  <Activities>    <Activity Name="Start" State="Start" IsInitial="True"              IsFinal="False" IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="100" Y="300" />    </Activity>    <Activity Name="LaunchTasks" State="LaunchTasks"              IsInitial="False" IsFinal="False"              IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="350" Y="300" />    </Activity>    <Activity Name="IT_Department" State="IT_Department"              IsInitial="False" IsFinal="False"              IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="700" Y="100" />    </Activity>    <Activity Name="HR_Department" State="HR_Department"              IsInitial="False" IsFinal="False"              IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="700" Y="300" />    </Activity>    <Activity Name="Facilities_Department" State="Facilities_Department"              IsInitial="False" IsFinal="False"              IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="700" Y="500" />    </Activity>    <Activity Name="Merged" State="Merged"              IsInitial="False" IsFinal="False"              IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="1050" Y="300" />    </Activity>    <Activity Name="Complete" State="Complete"              IsInitial="False" IsFinal="True"              IsForSetState="True"              IsAutoSchemeUpdate="True">      <Designer X="1400" Y="200" />    </Activity>  </Activities>  <Transitions>    <Transition Name="Start_LaunchTasks"                To="LaunchTasks" From="Start"                Classifier="Direct" IsFork="false"                MergeViaSetState="false"                DisableParentStateControl="false">      <Triggers>        <Trigger Type="Auto" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="LaunchTasks_IT"                To="IT_Department" From="LaunchTasks"                Classifier="NotSpecified"                IsFork="true"                MergeViaSetState="false"                DisableParentStateControl="false"                SubprocessInOutDefinition="Start"                SubprocessStartupType="SameThread"                SubprocessStartupParameterCopyStrategy="CopyAll">      <Triggers>        <Trigger Type="Auto" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="LaunchTasks_HR"                To="HR_Department" From="LaunchTasks"                Classifier="NotSpecified"                IsFork="true"                MergeViaSetState="false"                DisableParentStateControl="false"                SubprocessInOutDefinition="Start"                SubprocessStartupType="SameThread"                SubprocessStartupParameterCopyStrategy="CopyAll">      <Triggers>        <Trigger Type="Auto" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="LaunchTasks_Facilities"                To="Facilities_Department" From="LaunchTasks"                Classifier="NotSpecified"                IsFork="true"                MergeViaSetState="false"                DisableParentStateControl="false"                SubprocessInOutDefinition="Start"                SubprocessStartupType="SameThread"                SubprocessStartupParameterCopyStrategy="CopyAll">      <Triggers>        <Trigger Type="Auto" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="IT_Merged"                To="Merged" From="IT_Department"                Classifier="NotSpecified"                IsFork="true"                MergeViaSetState="false"                DisableParentStateControl="false"                SubprocessInOutDefinition="Finalize"                SubprocessFinalizeParameterMergeStrategy="OverwriteAllNulls">      <Triggers>        <Trigger Type="Command" NameRef="CompleteIT" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="HR_Merged"                To="Merged" From="HR_Department"                Classifier="NotSpecified"                IsFork="true"                MergeViaSetState="false"                DisableParentStateControl="false"                SubprocessInOutDefinition="Finalize"                SubprocessFinalizeParameterMergeStrategy="OverwriteAllNulls">      <Triggers>        <Trigger Type="Command" NameRef="CompleteHR" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="Facilities_Merged"                To="Merged" From="Facilities_Department"                Classifier="NotSpecified"                IsFork="true"                MergeViaSetState="false"                DisableParentStateControl="false"                SubprocessInOutDefinition="Finalize"                SubprocessFinalizeParameterMergeStrategy="OverwriteAllNulls">      <Triggers>        <Trigger Type="Command" NameRef="CompleteFacilities" />      </Triggers>      <Conditions>        <Condition Type="Always" />      </Conditions>      <Designer />    </Transition>    <Transition Name="Merged_Complete"                To="Complete" From="Merged"                Classifier="Direct" IsFork="false"                MergeViaSetState="false"                DisableParentStateControl="false">      <Triggers>        <Trigger Type="Auto" />      </Triggers>      <Conditions>        <Condition Type="Action"                   NameRef="CheckAllSubprocessesCompleted"                   ConditionInversion="false" />      </Conditions>      <Designer />    </Transition>  </Transitions></Process>

How the scheme works

Once the scheme is saved and BasicPlugin is registered with the WorkflowRuntime, the process runs as follows:

  1. Instance created - the Start activity runs and the Auto trigger moves the process to LaunchTasks.
  2. LaunchTasks forks - three Auto-triggered fork transitions (SubprocessInOutDefinition="Start") create child subprocesses for IT, HR, and Facilities. Each child runs independently and in parallel.
  3. Each subprocess waits - IT_Department, HR_Department, and Facilities_Department each wait for their respective commands (CompleteIT, CompleteHR, CompleteFacilities).
  4. Subprocess completes - when a command is executed on a subprocess, it transitions to Merged via SubprocessInOutDefinition="Finalize" and terminates.
  5. All complete - when all three subprocesses have finalized, CheckAllSubprocessesCompleted returns true on the Merged activity. The Auto trigger moves the process to Complete and it finalizes.

Reference

BasicPlugin provides the following actions and conditions for managing subprocess lifecycles.

CheckAllSubprocessesCompleted condition

Checks whether direct child subprocesses have finished. Mode controls whether child completion alone is enough or the current parent process must also be at the merge activity. The condition uses the process instance tree maintained by the runtime.

ParameterRequiredDefaultDescription
ModeYesAllSubprocessesSelects whether to wait only for direct child subprocesses or for them and the current parent process at the merge activity.

AllSubprocesses waits only for direct child subprocesses. It returns true when the current process node in ProcessInstancesTree has no active direct children.

AllSubprocessesAndParent waits for both parts of the merge: the direct child subprocesses must have finalized, and the current parent process must be at the merge activity. The runtime verifies the parent part with processInstance.ExecutedTransition.From.Name == processInstance.CurrentActivityName. Here, the parent is the current process that owns the subprocess branches, not a separate ancestor process.

DeleteSubprocesses action

Deletes all child subprocesses and their data. The action takes no parameters.

Enums

BasicPlugin uses the following enums in condition parameters.

CheckMode

The Mode parameter in CheckAllSubprocessesCompleted determines which processes are checked.

ValueBehavior
AllSubprocessesWait until all active direct child subprocesses have finished.
AllSubprocessesAndParentWait until all direct child subprocesses have finalized and the current parent process has reached the merge activity.

See also

Frequently asked questions

What is the difference between subprocesses and CreateProcess?

Subprocesses are created through fork transitions with SubprocessInOutDefinition="Start". They are tracked in the process tree and CheckAllSubprocessesCompleted checks them. The CreateProcess action creates an independent process instance that is not tracked as a subprocess.

How do I create parallel subprocesses?

Add multiple fork transitions from the same activity with IsFork="true", SubprocessInOutDefinition="Start", and distinct target activities. Each becomes a child subprocess.

How do I wait for all subprocesses to complete?

Add CheckAllSubprocessesCompleted as a condition on the merge transition. With Mode="AllSubprocesses", it returns true when all direct child subprocesses have finalized. With Mode="AllSubprocessesAndParent", the current process must also be at the merge activity.

How do I cancel subprocesses?

Use the DeleteSubprocesses action to remove all child processes. Add it to an activity implementation and transition to a cancellation state.