cloacina-workflow::retry
Rust
Retry Policy System
This module provides a comprehensive retry policy system for Cloacina tasks, including configurable backoff strategies, jitter, and conditional retry logic.
Overview
The retry system allows tasks to define sophisticated retry behavior:
- Configurable retry limits with per-task policies
- Multiple backoff strategies including exponential, linear, and custom
- Jitter support to prevent thundering herd problems
- Conditional retries based on error types and conditions
Usage
use cloacina_workflow::retry::{RetryPolicy, BackoffStrategy, RetryCondition};use std::time::Duration;
let policy = RetryPolicy::builder() .max_attempts(5) .backoff_strategy(BackoffStrategy::Exponential { base: 2.0, multiplier: 1.0 }) .initial_delay(Duration::from_millis(100)) .max_delay(Duration::from_secs(30)) .with_jitter(true) .retry_condition(RetryCondition::AllErrors) .build();Structs
Section titled “Structs”struct RetryPolicy
Section titled “struct 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
Section titled “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
Section titled “Methods”builder
Section titled “builder”pub
fn builder() -> RetryPolicyBuilderCreates a new RetryPolicyBuilder for fluent configuration.
Source
pub fn builder() -> RetryPolicyBuilder { RetryPolicyBuilder::new() }calculate_delay
Section titled “calculate_delay”pub
fn calculate_delay(&self, attempt: i32) -> DurationCalculates the delay before the next retry attempt.
Parameters:
| Name | Type | Description |
|---|---|---|
attempt |
i32 |
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
Section titled “should_retry”pub
fn should_retry(&self, error: &TaskError, attempt: i32) -> boolDetermines whether a retry should be attempted based on the error and retry conditions.
Parameters:
| Name | Type | Description |
|---|---|---|
error |
&TaskError |
The error that caused the task to fail |
attempt |
i32 |
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
Section titled “calculate_retry_at”pub
fn calculate_retry_at( &self, attempt: i32, now: NaiveDateTime,) -> NaiveDateTimeCalculates the absolute timestamp when the next retry should occur.
Parameters:
| Name | Type | Description |
|---|---|---|
attempt |
i32 |
The current attempt number |
now |
NaiveDateTime |
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() }struct RetryPolicyBuilder
Section titled “struct RetryPolicyBuilder”pub
Derives: Debug
Builder for creating RetryPolicy instances with a fluent API.
Methods
Section titled “Methods”pub
fn new() -> SelfCreates a new RetryPolicyBuilder with default values.
Source
pub fn new() -> Self { Self { policy: RetryPolicy::default(), } }max_attempts
Section titled “max_attempts”pub
fn max_attempts(mut self, max_attempts: i32) -> SelfSets 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
Section titled “backoff_strategy”pub
fn backoff_strategy(mut self, strategy: BackoffStrategy) -> SelfSets the backoff strategy.
Source
pub fn backoff_strategy(mut self, strategy: BackoffStrategy) -> Self { self.policy.backoff_strategy = strategy; self }initial_delay
Section titled “initial_delay”pub
fn initial_delay(mut self, delay: Duration) -> SelfSets 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
Section titled “max_delay”pub
fn max_delay(mut self, delay: Duration) -> SelfSets the maximum delay between retries.
Source
pub fn max_delay(mut self, delay: Duration) -> Self { self.policy.max_delay = delay; self }with_jitter
Section titled “with_jitter”pub
fn with_jitter(mut self, jitter: bool) -> SelfEnables or disables jitter.
Source
pub fn with_jitter(mut self, jitter: bool) -> Self { self.policy.jitter = jitter; self }retry_condition
Section titled “retry_condition”pub
fn retry_condition(mut self, condition: RetryCondition) -> SelfAdds a retry condition.
Source
pub fn retry_condition(mut self, condition: RetryCondition) -> Self { self.policy.retry_conditions = vec![condition]; self }retry_conditions
Section titled “retry_conditions”pub
fn retry_conditions(mut self, conditions: Vec<RetryCondition>) -> SelfAdds multiple retry conditions.
Source
pub fn retry_conditions(mut self, conditions: Vec<RetryCondition>) -> Self { self.policy.retry_conditions = conditions; self }pub
fn build(self) -> RetryPolicyBuilds the RetryPolicy.
Source
pub fn build(self) -> RetryPolicy { self.policy }enum BackoffStrategy
Section titled “enum 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
Section titled “Variants”Fixed- Fixed delay - same delay for every retry attemptLinear- Linear backoff - delay increases linearly with each attempt delay = initial_delay * attempt * multiplierExponential- Exponential backoff - delay increases exponentially with each attempt delay = initial_delay * multiplier * (base ^ attempt)Custom- Custom backoff function (reserved for future extensibility)
enum RetryCondition
Section titled “enum 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
Section titled “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