Skip to content

Subprocesses

A subprocess node runs another workflow as a child and resumes when that child completes. It is how a model is composed rather than duplicated: a "collect the applicant's documents" flow written once is called from every process that needs it, and the caller sees one step.

On reaching the node the engine starts a child instance and parks the parent token. Selected parent variables are passed in; when the child completes, the engine maps the child's variables back into the parent and resumes the parked token, so the outgoing flows route on what the child produced.

Because the parent parks like any other waiting step, everything that applies to a parked token applies here: timers can escalate or resume a parent whose child is taking too long, and a timeout that resumes the parent cancels the child still running under it.

Settings

n_collect:
  type: subprocess
  config:
    process: collect_documents
    input: |
      applicant
      case_reference: reference
    output: |
      documents
      verdict: collection_verdict
    completion_scope: instance
    state_variable: collection_state
    relaunch_attempts: 2
    relaunch_backoff: PT10M
  • process: the child workflow's machine name. The modeler offers every workflow as a select.
  • input: the parent variables to pass into the child, one per line. A bare name keeps the name across the boundary; name: child_name renames it.
  • output: the child variables to inject back into the parent when it completes, in the same one-per-line form, name or name: parent_name.
  • completion_scope: instance (the default, shared by the whole process) or token (local to this branch and its descendants), so parallel branches each calling the same child keep their own results apart.
  • state_variable: optional. Named, the parent resumes even when the child does not complete, with this variable set to __subprocess_failed__ or __subprocess_canceled__ so an outgoing flow condition can route the error. Left empty, the parent keeps waiting.
  • relaunch_attempts: how many times a failed child is re-launched as a fresh child before the parent gives up and resumes with the failed state. 0, the default, disables re-launching. Re-launches happen on cron, never inline.
  • relaunch_backoff: optional delay before each re-launch, in seconds or as an ISO-8601 duration (PT10M). Empty re-launches on the next cron run, and the node form rejects a value it cannot measure with rather than letting a typo quietly remove the delay. Config written directly, bypassing that validation, falls back to no delay.

Each attempt is counted against the parent token, so re-entering the node (a loop) starts a fresh budget rather than inheriting a spent one.

What a child inherits

A child runs in its parent's tenant and carries the parent instance's initiator, so a subprocess never crosses a tenant boundary and "who started this" survives the hop.

Of the parent's variables, only the ones input names cross over: the child does not see the rest, and its own writes reach the parent only through output. A child start is an ordinary start otherwise, so the child workflow's own declared variables are seeded as well, with the parent's input winning where the two name the same variable.

Execution and retention

Under synchronous execution a child is advanced inside the parent step's transaction, so the two commit together and a whole subtree drains in the one request. That whole subtree has to finish inside the advance lock's window, which is why a long-running child is a good reason to force queued execution for the caller. Under queued execution the child advances on its own cron turns while the parent stays parked.

A child instance is never purged while its parent is still running: it becomes eligible for retention once the parent finishes, and deleting an instance cascades to its subprocess children.