Skip to main content
Cloacina Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Retry

cloacina-workflow::retry Rust

Structs

cloacina-workflow::retry::RetryPolicy

pub

Derives: Debug, Clone, Serialize, Deserialize, PartialEq

Comprehensive retry policy configuration for tasks.

This struct defines how a task should behave when it fails, including the number of retry attempts, backoff strategy, delays, and conditions under which retries should be attempted.

Fields

Name Type Description
max_attempts i32 Maximum number of retry attempts (not including the initial attempt)
backoff_strategy BackoffStrategy The backoff strategy to use for calculating delays between retries
initial_delay Duration Initial delay before the first retry attempt
max_delay Duration Maximum delay between retry attempts (caps exponential growth)
jitter bool Whether to add random jitter to delays to prevent thundering herd
retry_conditions Vec < RetryCondition > Conditions that determine whether a retry should be attempted

Methods

builder pub
fn builder () -> RetryPolicyBuilder

Creates a new RetryPolicyBuilder for fluent configuration.

Source
    pub fn builder() -> RetryPolicyBuilder {
        RetryPolicyBuilder::new()
    }
calculate_delay pub
fn calculate_delay (& self , attempt : i32) -> Duration

Calculates the delay before the next retry attempt.

Parameters:

Name Type Description
attempt - The current attempt number (1-based)

Returns:

The duration to wait before the next retry attempt.

Source
    pub fn calculate_delay(&self, attempt: i32) -> Duration {
        let base_delay = match &self.backoff_strategy {
            BackoffStrategy::Fixed => self.initial_delay,

            BackoffStrategy::Linear { multiplier } => {
                let millis = self.initial_delay.as_millis() as f64 * attempt as f64 * multiplier;
                Duration::from_millis(millis as u64)
            }

            BackoffStrategy::Exponential { base, multiplier } => {
                let millis =
                    self.initial_delay.as_millis() as f64 * multiplier * base.powi(attempt - 1);
                Duration::from_millis(millis as u64)
            }

            BackoffStrategy::Custom { .. } => {
                // For now, fall back to exponential backoff for custom functions
                let millis = self.initial_delay.as_millis() as f64 * 2.0_f64.powi(attempt - 1);
                Duration::from_millis(millis as u64)
            }
        };

        // Cap the delay at max_delay
        let capped_delay = std::cmp::min(base_delay, self.max_delay);

        // Add jitter if enabled
        if self.jitter {
            self.add_jitter(capped_delay)
        } else {
            capped_delay
        }
    }
should_retry pub
fn should_retry (& self , error : & TaskError , attempt : i32) -> bool

Determines whether a retry should be attempted based on the error and retry conditions.

Parameters:

Name Type Description
error - The error that caused the task to fail
attempt - The current attempt number

Returns:

true if the task should be retried, false otherwise.

Source
    pub fn should_retry(&self, error: &TaskError, attempt: i32) -> bool {
        // Check if we've exceeded the maximum number of attempts
        if attempt >= self.max_attempts {
            return false;
        }

        // Check retry conditions
        self.retry_conditions
            .iter()
            .any(|condition| match condition {
                RetryCondition::AllErrors => true,
                RetryCondition::Never => false,
                RetryCondition::TransientOnly => self.is_transient_error(error),
                RetryCondition::ErrorPattern { patterns } => {
                    let error_msg = error.to_string().to_lowercase();
                    patterns
                        .iter()
                        .any(|pattern| error_msg.contains(&pattern.to_lowercase()))
                }
            })
    }
calculate_retry_at pub
fn calculate_retry_at (& self , attempt : i32 , now : NaiveDateTime) -> NaiveDateTime

Calculates the absolute timestamp when the next retry should occur.

Parameters:

Name Type Description
attempt - The current attempt number
now - The current timestamp

Returns:

A NaiveDateTime representing when the retry should be attempted.

Source
    pub fn calculate_retry_at(&self, attempt: i32, now: NaiveDateTime) -> NaiveDateTime {
        let delay = self.calculate_delay(attempt);
        now + chrono::Duration::from_std(delay).unwrap_or_default()
    }
add_jitter private
fn add_jitter (& self , delay : Duration) -> Duration

Adds random jitter to a delay to prevent thundering herd problems.

Uses +/-25% jitter by default.

Source
    fn add_jitter(&self, delay: Duration) -> Duration {
        let mut rng = rand::thread_rng();
        let jitter_factor = rng.gen_range(0.75..=1.25); // +/-25% jitter
        let jittered_millis = (delay.as_millis() as f64 * jitter_factor) as u64;
        Duration::from_millis(jittered_millis)
    }
is_transient_error private
fn is_transient_error (& self , error : & TaskError) -> bool

Determines if an error is transient (network, timeout, temporary failures).

Source
    fn is_transient_error(&self, error: &TaskError) -> bool {
        match error {
            TaskError::Timeout { .. } => true,
            TaskError::ExecutionFailed { message, .. } | TaskError::Unknown { message, .. } => {
                Self::message_matches_transient_patterns(message)
            }
            _ => false,
        }
    }
message_matches_transient_patterns private
fn message_matches_transient_patterns (message : & str) -> bool

Checks whether an error message contains any known transient error patterns.

Source
    fn message_matches_transient_patterns(message: &str) -> bool {
        const TRANSIENT_PATTERNS: &[&str] = &[
            "connection",
            "network",
            "timeout",
            "temporary",
            "unavailable",
            "busy",
            "overloaded",
            "rate limit",
        ];
        let error_msg = message.to_lowercase();
        TRANSIENT_PATTERNS
            .iter()
            .any(|pattern| error_msg.contains(pattern))
    }

cloacina-workflow::retry::RetryPolicyBuilder

pub

Derives: Debug

Builder for creating RetryPolicy instances with a fluent API.

Fields

Name Type Description
policy RetryPolicy

Methods

new pub
fn new () -> Self

Creates a new RetryPolicyBuilder with default values.

Source
    pub fn new() -> Self {
        Self {
            policy: RetryPolicy::default(),
        }
    }
max_attempts pub
fn max_attempts (mut self , max_attempts : i32) -> Self

Sets the maximum number of retry attempts.

Source
    pub fn max_attempts(mut self, max_attempts: i32) -> Self {
        self.policy.max_attempts = max_attempts;
        self
    }
backoff_strategy pub
fn backoff_strategy (mut self , strategy : BackoffStrategy) -> Self

Sets the backoff strategy.

Source
    pub fn backoff_strategy(mut self, strategy: BackoffStrategy) -> Self {
        self.policy.backoff_strategy = strategy;
        self
    }
initial_delay pub
fn initial_delay (mut self , delay : Duration) -> Self

Sets the initial delay before the first retry.

Source
    pub fn initial_delay(mut self, delay: Duration) -> Self {
        self.policy.initial_delay = delay;
        self
    }
max_delay pub
fn max_delay (mut self , delay : Duration) -> Self

Sets the maximum delay between retries.

Source
    pub fn max_delay(mut self, delay: Duration) -> Self {
        self.policy.max_delay = delay;
        self
    }
with_jitter pub
fn with_jitter (mut self , jitter : bool) -> Self

Enables or disables jitter.

Source
    pub fn with_jitter(mut self, jitter: bool) -> Self {
        self.policy.jitter = jitter;
        self
    }
retry_condition pub
fn retry_condition (mut self , condition : RetryCondition) -> Self

Adds a retry condition.

Source
    pub fn retry_condition(mut self, condition: RetryCondition) -> Self {
        self.policy.retry_conditions = vec![condition];
        self
    }
retry_conditions pub
fn retry_conditions (mut self , conditions : Vec < RetryCondition >) -> Self

Adds multiple retry conditions.

Source
    pub fn retry_conditions(mut self, conditions: Vec<RetryCondition>) -> Self {
        self.policy.retry_conditions = conditions;
        self
    }
build pub
fn build (self) -> RetryPolicy

Builds the RetryPolicy.

Source
    pub fn build(self) -> RetryPolicy {
        self.policy
    }

Enums

cloacina-workflow::retry::BackoffStrategy pub

Different backoff strategies for calculating retry delays.

Each strategy defines how the delay between retry attempts should increase. The actual delay is calculated based on the attempt number and the strategy’s parameters.

Variants

  • Fixed - Fixed delay - same delay for every retry attempt
  • Linear - Linear backoff - delay increases linearly with each attempt delay = initial_delay * attempt * multiplier
  • Exponential - Exponential backoff - delay increases exponentially with each attempt delay = initial_delay * multiplier * (base ^ attempt)
  • Custom - Custom backoff function (reserved for future extensibility)

cloacina-workflow::retry::RetryCondition pub

Conditions that determine whether a failed task should be retried.

These conditions are used to evaluate whether a task should be retried based on the type of error or specific error patterns.

Variants

  • AllErrors - Retry on all errors (default behavior)
  • Never - Never retry (equivalent to max_attempts = 0)
  • TransientOnly - Retry only for transient errors (network, timeout, etc.)
  • ErrorPattern - Retry only if error message contains any of the specified patterns