Activity Timeouts - Rust SDK
Set Activity timeouts
Each Activity timeout controls the maximum duration of a different aspect of an Activity Execution.
The following timeouts are available in Activity options:
- Schedule-To-Close Timeout: the maximum amount of time allowed for the overall Activity Execution.
- Start-To-Close Timeout: the maximum time allowed for a single Activity Task Execution.
- Schedule-To-Start Timeout: the maximum amount of time allowed from when an Activity Task is scheduled to when a Worker starts that Activity Task.
An Activity Execution must have either the Start-To-Close Timeout or the Schedule-To-Close Timeout set. Temporal strongly recommends setting a Start-To-Close Timeout because the service relies on it to detect lost Activity Tasks and trigger retries when appropriate.
In Rust, these values are configured as part of the Activity options when scheduling an Activity from a Workflow. The Rust SDK is currently pre-release and its API is still evolving, so exact method names may change over time.
Available timeout fields include:
schedule_to_close_timeoutschedule_to_start_timeoutstart_to_close_timeout
let greeting = ctx.start_activity(
MyActivities::greet,
name,
ActivityOptions::start_to_close_timeout(Duration::from_secs(30))
);
Set an Activity Retry Policy
A Retry Policy works together with timeouts to provide fine-grained control over Activity failure handling. Activities automatically use a default Retry Policy unless you provide a custom one.
In Rust, configure the Retry Policy as part of the Activity options when scheduling the Activity from Workflow code. Because the Rust SDK API is still evolving, treat the following as representative of the current style rather than a guaranteed stable surface.
let language = ctx.start_activity(
MyActivities::call_greeting_service,
ActivityLanguages::English,
ActivityOptions::with_start_to_close_timeout(Duration::from_secs(30))
.retry_policy(
RetryPolicy {
initial_interval: Some(prost_dur!(from_secs(10))),
backoff_coefficient: 2.0,
maximum_interval: Some(prost_dur!(from_secs(100))),
maximum_attempts: 5,
non_retryable_error_types: vec!["NonRetryableError".to_string()]
}
).build()
);
Override the retry interval with explicit_delay
To override the next retry interval set by the current policy, return a failure from an Activity with a custom next retry delay. That value replaces the interval the Retry Policy would otherwise use for the next retry attempt. This is useful when retry timing depends on runtime state such as the current attempt number.
For example, you can increase the delay linearly with each attempt instead of using the exponential backoff defined by a backoff coefficient:
use temporalio_macros::{activities};
use temporalio_sdk::activities::{ActivityContext, ActivityError};
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
struct TestGreetActivities {
counter: AtomicUsize,
}
#[activities]
impl TestGreetActivities {
#[activity]
pub async fn greet(_ctx: ActivityContext, name: String) -> Result<String, ActivityError> {
if name == "ziggy" {
return Err(ApplicationFailure::builder(anyhow::anyhow!("Ziggy is not a valid name"))
// next retry will be after 5 seconds
.next_retry_delay(std::time::Duration::from_secs(5))
.build()
.into());
}
Ok(format!("Hello, {}!", name))
}
}
Heartbeat an Activity
An Activity Heartbeat is a signal from the Worker Process executing the Activity to the Temporal Service. Each heartbeat tells the service that the Activity Execution is still making progress and that the Worker has not crashed. If the service does not receive a heartbeat within the configured Heartbeat Timeout, the Activity can time out and be retried according to its Retry Policy.
Heartbeats may be throttled by the Worker, so not every heartbeat call is necessarily sent immediately to the Temporal Service. Activity cancellation is also delivered through heartbeat processing, which means Activities that don't heartbeat cannot receive cancellation promptly. ([Temporal Docs][3])
Heartbeats can include details that describe current progress. If the Activity fails and is retried, the retried attempt can retrieve the details from the most recently recorded heartbeat. The Rust SDK exposes activity context support for heartbeat details.
To heartbeat an Activity in Rust, call the heartbeat API from inside the Activity with record_heartbeat:
pub async fn greet(ctx: ActivityContext, name: String) -> Result<String, ActivityError> {
ctx.record_heartbeat(vec!["greet activity started".into()]);
if name == "ziggy" {
return Err(anyhow::anyhow!("Ziggy is not a valid name").into());
}
Ok(format!("Hello, {}!", name))
}
Set a Heartbeat Timeout
A Heartbeat Timeout works together with Activity heartbeats and sets the maximum time allowed between heartbeats. Configure it as part of the Activity options when scheduling the Activity.
let language = ctx.start_activity(
MyActivities::call_greeting_service,
ActivityLanguages::English,
ActivityOptions::with_start_to_close_timeout(Duration::from_secs(30))
.heartbeat_timeout(Duration::from_secs(5))
.build()
);