Nested Sub-Workflows
Sub-workflows calling sub-workflows — depth limits, cycle detection, and practical nesting patterns for hierarchical workflow architectures.
Depth Limit
The engine enforces a maximum nesting depth of 5 levels. A depth counter is tracked on each execution record via the SubWorkflowDepth field. When a SubWorkflow node attempts to start a child, the engine checks:
if (parentExecution.SubWorkflowDepth >= 5)
{
throw new SubWorkflowDepthExceededException(
$"Cannot nest sub-workflows deeper than 5 levels. Current depth: {parentExecution.SubWorkflowDepth}");
}
Cycle Detection
The engine prevents circular sub-workflow references at load time when a process is published. It builds a dependency graph of all processes and their sub-workflow references, then checks for cycles using DFS:
Process A → calls Process B → calls Process C → calls Process A [CYCLE DETECTED]
Process A → calls Process B → calls Process C [OK]
A process with a circular dependency cannot be published. The designer shows a validation error indicating which process creates the cycle.
The Ancestry Chain
Each execution record stores its full ancestry chain:
{
"executionId": "exec-103",
"parentExecutionId": "exec-102",
"rootExecutionId": "exec-100",
"subWorkflowDepth": 3,
"ancestorExecutionIds": ["exec-100", "exec-101", "exec-102"]
}
This ancestry chain enables the observer panel to display the full parent/child execution hierarchy.
Practical Nesting Example
Depth 0: PurchaseOrderApproval
└── Depth 1: FinanceApproval (sync)
└── Depth 2: DelegateApproval (sync)
└── Depth 3: SendApprovalNotification (async)
This 4-level hierarchy is well within the limit. The root workflow PurchaseOrderApproval calls FinanceApproval, which delegates to DelegateApproval, which fires an async notification workflow.
Cross-Tenant Sub-Workflows
Sub-workflows always run within the same tenant as the parent. Cross-tenant invocation is blocked at the engine level — the tenantId is inherited from the parent execution and cannot be overridden by the SubWorkflow node config.