Skip to main content

Child Workflows

How to start a Child Workflow Execution

A Child Workflow Execution is a Workflow Execution that is scheduled from within another Workflow using a Child Workflow API.

When using a Child Workflow API, Child Workflow–related Events (such as StartChildWorkflowExecutionInitiated, ChildWorkflowExecutionStarted, and ChildWorkflowExecutionCompleted) are logged in the Event History of the Child Workflow Execution.

Always block progress until the ChildWorkflowExecutionStarted Event is logged to the Event History to ensure the Child Workflow Execution has started. After that, Child Workflow Executions can be abandoned by using the default Abandon Parent Close Policy set in the Child Workflow Options.

To be sure that the Child Workflow Execution has started, first call the Child Workflow Execution method on the instance of Child Workflow future, which returns a different future.

Then get the value of an object that acts as a proxy for a result that is initially unknown, which is what waits until the Child Workflow Execution has spawned.

To start a Child Workflow Execution and return a handle to it, use startChild.

import { startChild } from '@temporalio/workflow';

export async function parentWorkflow(names: string[]) {
const childHandle = await startChild(childWorkflow, {
args: [name],
// workflowId, // add business-meaningful workflow id here
// // regular workflow options apply here, with two additions (defaults shown):
// cancellationType: ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED,
// parentClosePolicy: ParentClosePolicy.PARENT_CLOSE_POLICY_TERMINATE
});
// you can use childHandle to signal or get result here
await childHandle.signal('anySignal');
const result = childHandle.result();
// you can use childHandle to signal, query, cancel, terminate, or get result here
}

To start a Child Workflow Execution and await its completion, use executeChild.

By default, a child is scheduled on the same Task Queue as the parent.

child-workflows/src/workflows.ts

import { executeChild } from '@temporalio/workflow';

export async function parentWorkflow(...names: string[]): Promise<string> {
const responseArray = await Promise.all(
names.map((name) =>
executeChild(childWorkflow, {
args: [name],
// workflowId, // add business-meaningful workflow id here
// // regular workflow options apply here, with two additions (defaults shown):
// cancellationType: ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED,
// parentClosePolicy: ParentClosePolicy.PARENT_CLOSE_POLICY_TERMINATE
})
),
);
return responseArray.join('\n');
}

To control any running Workflow from inside a Workflow, use getExternalWorkflowHandle(workflowId).

import { getExternalWorkflowHandle, workflowInfo } from '@temporalio/workflow';

export async function terminateWorkflow() {
const { workflowId } = workflowInfo(); // no await needed
const handle = getExternalWorkflowHandle(workflowId); // sync function, not async
await handle.cancel();
}

If the Child Workflow options aren't explicitly set, they inherit their values from the Parent Workflow options. Two advanced options are unique to Child Workflows:

  • cancellationType: Controls when to throw the CanceledFailure exception when a Child Workflow is canceled.
  • parentClosePolicy: Explained in the next section.

If you need to cancel a Child Workflow Execution, use cancellation scopes. A Child Workflow Execution is automatically cancelled when its containing scope is cancelled.

How to set a Parent Close Policy

A Parent Close Policy determines what happens to a Child Workflow Execution if its Parent changes to a Closed status (Completed, Failed, or Timed Out).

The default Parent Close Policy option is set to terminate the Child Workflow Execution.

To specify how a Child Workflow reacts to a Parent Workflow reaching a Closed state, use the parentClosePolicy option.

child-workflows/src/workflows.ts

import { executeChild } from '@temporalio/workflow';

export async function parentWorkflow(...names: string[]): Promise<string> {
const responseArray = await Promise.all(
names.map((name) =>
executeChild(childWorkflow, {
args: [name],
// workflowId, // add business-meaningful workflow id here
// // regular workflow options apply here, with two additions (defaults shown):
// cancellationType: ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED,
// parentClosePolicy: ParentClosePolicy.PARENT_CLOSE_POLICY_TERMINATE
})
),
);
return responseArray.join('\n');
}