Skip to main content

Child Workflows - Rust SDK

This page shows how to do the following:

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 are logged in the Workflow Execution Event History.

Always wait until the Child Workflow Execution has started before moving on. Using PendingChildWorkflow ensures this.

To start a Child Workflow in Rust, use ctx.child_workflow():

use temporalio_common::protos::temporal::api::common::v1::Payload;
use temporalio_macros::{workflow, workflow_methods};
use temporalio_sdk::{ChildWorkflowOptions, WorkflowContext, WorkflowContextView, WorkflowResult};

// child workflow
#[workflow]
pub struct ComposeGreetingWorkflow {
pub name: String,
}

#[workflow_methods]
impl ComposeGreetingWorkflow {
#[init]
fn new(_ctx: &WorkflowContextView, name: String) -> Self {
Self { name }
}

#[run]
pub async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<String> {
let name = ctx.state(|s| s.name.clone());
Ok(format!("Hello from child: {}", name))
}
}

// parent workflow
#[workflow]
pub struct GreetingWorkflow {
pub name: String,
}

#[workflow_methods]
impl GreetingWorkflow {
#[init]
fn new(_ctx: &WorkflowContextView, name: String) -> Self {
Self { name }
}

#[run]
pub async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<String> {
let name = ctx.state(|s| s.name.clone());

let input = vec![
Payload {
data: name.as_bytes().to_vec(),
..Default::default()
}
];
let child_opts = ChildWorkflowOptions {
input,
workflow_id: "compose-greeting-child-workflow-id".to_string(),
workflow_type: "ComposeGreetingWorkflow".to_string(),
..Default::default()
};

let started = ctx.child_workflow(child_opts).start().await.into_started().unwrap();
let result = started.result().await;

Ok(format!("ComposeGreetingWorkflow result: {:?}", result))
}
}

Specify Child Workflow options

Use ChildWorkflowOptions to customize Child Workflow behavior.

Execute multiple Child Workflows in parallel

You can start multiple Child Workflows and wait for all of them:

use temporalio_common::protos::{temporal::api::common::v1::Payload};
use temporalio_macros::{workflow, workflow_methods};
use temporalio_sdk::{ChildWorkflowOptions, WorkflowContext, WorkflowContextView, WorkflowResult};

// define child workflow 1
#[workflow]
pub struct ComposeEnGreetingWorkflow {
pub name: String,
}

#[workflow_methods]
impl ComposeEnGreetingWorkflow {
#[init]
fn new(_ctx: &WorkflowContextView, name: String) -> Self {
Self { name }
}

#[run]
pub async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<String> {
let name = ctx.state(|s| s.name.clone());
Ok(format!("Hello: {}", name))
}
}

// define child workflow 2
#[workflow]
pub struct ComposeEsGreetingWorkflow {
pub name: String,
}

#[workflow_methods]
impl ComposeEsGreetingWorkflow {
#[init]
fn new(_ctx: &WorkflowContextView, name: String) -> Self {
Self { name }
}

#[run]
pub async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<String> {
let name = ctx.state(|s| s.name.clone());
Ok(format!("Hola: {}", name))
}
}

#[workflow]
pub struct GreetingWorkflow {
pub name: String,
}

#[workflow_methods]
impl GreetingWorkflow {
#[init]
fn new(_ctx: &WorkflowContextView, name: String) -> Self {
Self { name }
}

#[run]
pub async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<Vec<Option<String>>> {
let name = ctx.state(|s| s.name.clone());

let input = vec![
Payload {
data: name.as_bytes().to_vec(),
..Default::default()
}
];
let greeting_opts = ChildWorkflowOptions {
input,
workflow_id: "compose-greeting-child-workflow-id".to_string(),
workflow_type: "ComposeGreetingWorkflow".to_string(),
..Default::default()
};

let en_greeting_child = ctx.child_workflow(greeting_opts.clone()).start().await.into_started().unwrap();
let es_greeting_child = ctx.child_workflow(ChildWorkflowOptions {
workflow_id: "compose-spanish-greeting-child-workflow-id".to_string(),
..greeting_opts.clone()
}).start().await.into_started().unwrap();

let en_result = en_greeting_child.result().await.status.map(|s| format!("{:?}", s));
let es_result = es_greeting_child.result().await.status.map(|s| format!("{:?}", s));

let combined = vec![en_result, es_result];

Ok(combined)
}
}

Both child Workflows run in parallel and the parent waits for both to complete.

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 is set to terminate the Child Workflow Execution.

Set Parent Close Policy using the parent_close_policy field in ChildWorkflowOptions:

use temporalio_common::protos::temporal::api::{enums::v1::ParentClosePolicy};

let child_opts = ChildWorkflowOptions {
input,
workflow_id: "compose-greeting-child-workflow-id".to_string(),
workflow_type: "ComposeGreetingWorkflow".to_string(),
parent_close_policy: ParentClosePolicy::Abandon,
..Default::default()
};

Parent Close Policy Options

  • Terminate (default) - The Child Workflow will be terminated immediately when the parent closes
  • Abandon - The Child Workflow will continue running even if the parent closes
  • RequestCancel - The Child Workflow will receive a cancellation request when the parent closes