Sub-Workflows & Contract
Die Activity startWorkflow startet einen anderen Workflow. Der aufrufende Workflow ist der Parent, der gestartete Workflow der Child. Der Child erhält einen eigenen Dependency-Injection-Scope.
Modus
waitForCompletion: true(Standard) → Parent wartet auf den Child. Child-returnDatawird alsparam.*in den Parent gespiegelt.waitForCompletion: false→ fire-and-forget. Parent erhältparam.workflowId/param.workflowName/param.executionId/param.waited.
Max Call-Depth: 10. forEach teilt sich das ISubWorkflowGate mit startWorkflow.
Contract-Derivation
GET /{id}/contract liefert die Schnittstelle eines Workflows:
- Inputs aus
manualTrigger.parameters. - Outputs aus
returnData.data-Keys + System-Outputs (__executionId,__status,__workflowId,__workflowName).
Aufrufer ohne Edit-Recht auf den Ordner des Workflows sehen bei jedem Input mit Default *** statt des Werts. Die Maske betrifft nur die Anzeige; ein nicht gesetzter Parameter bekommt zur Laufzeit weiterhin den echten Default.
By-name-Lookup: exakte Schreibweise gewinnt, sonst case-insensitive — mehrdeutige Namen (Name ist nicht unique) liefern 409 statt eines stillen Zufallstreffers. Die Engine (startWorkflow/forEach) löst identisch auf, damit der Designer nie einen Contract zeigt, den die Runtime nicht findet.
Feinheiten
HasManualTrigger=falseheißt nicht "nicht aufrufbar" —startWorkflowkann jeden enabled Workflow aufrufen. Es bedeutet nur: kein deklarierter Input-Contract; die UI fällt auf eine freie Parameter-Tabelle zurück.- Mehrere
returnData-Nodes:HasMultipleReturnDataNodes=true. Pro Lauf gewinnt nur einer (last-write-wins über das ganze JSON, nicht per Key). Outputs sind "may be available", nicht garantiert — die UI zeigt eine Warning. - Mehrere
manualTrigger: Parameter werden nach Namen dedupliziert. Bei divergierendemtype/defaultgewinnt die erste Deklaration,HasConflict=true— UI-Warning, kein Hard-Fail.Requiredwird OR-aggregiert. - Reservierte Output-Keys (
__executionId,__status,__workflowId,__workflowName) werden aus User-returnData.datastill gefiltert und separat von der Engine injiziert. - Disabled Nodes (
manualTrigger/returnDatamitdata.disabled=true) werden ignoriert — entspricht dem Engine-Skip-Verhalten.