Skip to main content

Continue-As-New

View Markdown

This page covers the following for Rust developers:

What is Continue-As-New?​

Continue-As-New lets a Workflow execution close successfully and creates a new Workflow execution. You can think of it as a checkpoint when your Workflow gets too long or approaches certain scaling limits.

The new Workflow execution is in the same chain; it keeps the same Workflow ID but gets a new Run Id and a fresh Event History. It also receives your Workflow's usual parameters.

Use Continue-As-New​

First, design your Workflow parameters so that you can pass in the "current state" when you Continue-As-New into the next Workflow run. This state is typically passed as a parameter or stored in the Workflow struct.

Inside your Workflow, call ctx.continue_as_new() and propagate its result:

rust-sandbox/workflows/continue-as-new/src/basic.rs

use std::time::Duration;

use temporalio_macros::{workflow, workflow_methods};
use temporalio_sdk::{ActivityOptions, ContinueAsNewOptions, WorkflowContext, WorkflowResult};

use crate::activities::MyActivities;

#[workflow]
#[derive(Default)]
pub struct GreetingWorkflow;

#[workflow_methods]
impl GreetingWorkflow {
#[run(name = "greeting-workflow-1")]
pub async fn run(ctx: &mut WorkflowContext<Self>, name: String) -> WorkflowResult<String> {
let greeting = ctx
.execute_activity(
MyActivities::greet,
name.clone(),
ActivityOptions::start_to_close_timeout(Duration::from_secs(30)),
)
.await?;

if name == "Ziggy" {
Ok(greeting)
} else {
// continue_as_new() always returns an error that ends this run.
// Propagate it with `?`. The empty match tells the compiler that
// nothing runs after it.
match ctx.continue_as_new("Ziggy".to_string(), ContinueAsNewOptions::default())? {}
}
}
}

The ctx.continue_as_new() method accepts the input to pass to the next Workflow Run. It returns Result<Infallible, WorkflowTermination> and always returns the Err variant, which ends the current run. Propagate it with ? inside an empty match, so the compiler knows the branch doesn't continue.

When is it right to Continue-As-New with the Rust SDK?​

Use Continue-as-New when your Workflow might encounter degraded performance or Event History Limits.

Temporal tracks your Workflow's progress against these limits to let you know when you should Continue-as-New. Call ctx.continue_as_new_suggested() to check if it's time.

Test Continue-As-New with the Rust SDK​

Testing Workflows that naturally Continue-as-New may be time-consuming and resource-intensive. Instead, add a test hook to check your Workflow's Continue-as-New behavior faster in automated tests.

This sample takes a max_history_length input that a test can set to a small value. A helper method in the Workflow impl checks it each time the Workflow considers Continue-as-New. When the Workflow continues, it passes the number of greetings left to the next run:

rust-sandbox/workflows/continue-as-new/src/test_hook.rs

use std::time::Duration;

use serde::{Deserialize, Serialize};
use temporalio_macros::{workflow, workflow_methods};
use temporalio_sdk::{ActivityOptions, ContinueAsNewOptions, WorkflowContext, WorkflowResult};

use crate::activities::MyActivities;

#[derive(Serialize, Deserialize)]
pub struct GreetingInput {
pub name: String,
pub greetings_remaining: u32,
pub max_history_length: u32,
}

#[workflow]
#[derive(Default)]
pub struct RepeatGreetingWorkflow;

#[workflow_methods]
impl RepeatGreetingWorkflow {
#[run]
pub async fn run(
ctx: &mut WorkflowContext<Self>,
input: GreetingInput,
) -> WorkflowResult<String> {
let mut greetings_remaining = input.greetings_remaining;

while greetings_remaining > 0 {
ctx.execute_activity(
MyActivities::greet,
input.name.clone(),
ActivityOptions::start_to_close_timeout(Duration::from_secs(30)),
)
.await?;
greetings_remaining -= 1;

if greetings_remaining > 0
&& Self::should_continue_as_new(ctx, input.max_history_length)
{
// Pass the state the next run needs.
let next_input = GreetingInput {
greetings_remaining,
..input
};
match ctx.continue_as_new(next_input, ContinueAsNewOptions::default())? {}
}
}

Ok(format!("Sent all greetings to {}", input.name))
}

fn should_continue_as_new(ctx: &WorkflowContext, max_history_length: u32) -> bool {
if ctx.continue_as_new_suggested() {
return true;
}

// For testing
if max_history_length > 0 && ctx.history_length() > max_history_length {
return true;
}

false
}
}

Best practices​

  1. Pass all necessary state: When continuing as new, include all state the next run needs.
  2. Use meaningful iteration markers: Include iteration numbers or timestamps to track progress.
  3. Test your state passing: Ensure parameters serialize and deserialize correctly.
  4. Don't continue-as-new too frequently: It's better to have some Event History than to continue-as-new on every execution.
  5. Consider batch sizes: Find the right balance between batch size and number of continues as new.