pub struct RetryExecutor<T, C: RetryConfig = DefaultRetryConfig> { /* private fields */ }Expand description
Retry executor
Responsible for executing operations with retry strategies. Automatically executes retry logic according to configured retry strategies, delay strategies, failure/abort conditions, and triggers event listeners at appropriate times.
§Generic Parameters
T- The return value type of the operationC- Retry configuration type, must implementRetryConfigtrait, defaults toDefaultRetryConfig
§Core Features
- Synchronous Retry:
run()method executes synchronous operations, using post-check mechanism for timeout detection - Asynchronous Retry:
run_async()method executes asynchronous operations, using tokio::time::timeout for real timeout interruption - Timeout Control: Supports single operation timeout (operation_timeout) and overall timeout (max_duration)
- Event Listening: Supports event callbacks for retry, success, failure, abort, etc.
- Flexible Configuration: Supports multiple delay strategies, error type identification, result value judgment, etc.
§Timeout Control
The executor supports two levels of timeout control:
-
Single Operation Timeout (operation_timeout):
- Controls the maximum execution time for each operation
- Synchronous version (
run): Checks if timeout occurred after operation completes (post-check mechanism) - Asynchronous version (
run_async): Uses tokio::time::timeout to truly interrupt timeout operations
-
Overall Timeout (max_duration):
- Controls the maximum total time for the entire retry process (including all retries and delays)
- Applies to both synchronous and asynchronous versions
§Usage Examples
§Synchronous Retry (Post-Check Timeout)
use prism3_retry::{RetryBuilder, RetryResult};
use std::time::Duration;
let executor = RetryBuilder::<String>::new()
.set_max_attempts(3)
.set_operation_timeout(Some(Duration::from_secs(5)))
.build();
// Use RetryResult type alias to simplify function signature
let result: RetryResult<String> = executor.run(|| {
// Can directly return any error type that implements Into<RetryError>
// For example, using ? operator to handle io::Error will automatically
// convert to RetryError
std::thread::sleep(Duration::from_millis(100));
Ok("SUCCESS".to_string())
});§Asynchronous Retry (Real Timeout Interruption)
use prism3_retry::{RetryBuilder, RetryResult};
use std::time::Duration;
let executor = RetryBuilder::<String>::new()
.set_max_attempts(3)
.set_operation_timeout(Some(Duration::from_secs(5)))
.build();
// Use RetryResult to make async function signature clearer
let result: RetryResult<String> = executor.run_async(|| async {
// Asynchronous operation, truly interrupted on timeout
tokio::time::sleep(Duration::from_millis(100)).await;
Ok("SUCCESS".to_string())
}).await;§Author
Haixing Hu
Implementations§
Source§impl<T, C> RetryExecutor<T, C>
impl<T, C> RetryExecutor<T, C>
Sourcepub fn run<F>(&self, operation: F) -> RetryResult<T>
pub fn run<F>(&self, operation: F) -> RetryResult<T>
Execute synchronous operation (with post-check timeout mechanism)
Execute synchronous operation according to configured retry strategy, until success, maximum retry count reached, or abort condition met.
§Timeout Control
This method uses post-check mechanism for timeout control:
- After operation completes, check if execution time exceeds
operation_timeout - If timeout, convert result to
RetryError::OperationTimeouterror and trigger retry - Note: Cannot truly interrupt ongoing synchronous operation
If you need to truly interrupt timeout operations, please use
run_async() method.
§Parameters
operation- Operation to execute, returnsResult<T, Box<dyn Error + Send + Sync>>
§Returns
Returns operation result or error
§Example
use prism3_retry::{RetryBuilder, RetryDelayStrategy, RetryResult};
use std::time::Duration;
let executor = RetryBuilder::new()
.set_max_attempts(3)
.set_delay_strategy(RetryDelayStrategy::Fixed { delay: Duration::from_secs(1) })
.set_operation_timeout(Some(Duration::from_secs(5))) // Single operation post-check timeout
.build();
// Use RetryResult to simplify function signature, leveraging From trait
// for automatic error conversion
let result: RetryResult<String> = executor.run(|| -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
// Can return any standard error type, will be automatically
// converted to RetryError
// Example: std::fs::File::open("file.txt")?;
// io::Error will be automatically converted to RetryError through
// From trait
Ok("SUCCESS".to_string())
});
assert!(result.is_ok());Sourcepub async fn run_async<F, Fut>(&self, operation: F) -> RetryResult<T>
pub async fn run_async<F, Fut>(&self, operation: F) -> RetryResult<T>
Execute asynchronous operation (with real timeout interruption)
Execute asynchronous operation according to configured retry strategy, with single operation timeout control.
§Timeout Control
This method uses tokio::time::timeout for real timeout interruption:
- When operation execution time exceeds
operation_timeout, the operation will be truly interrupted (cancelled) - After interruption, retry will be triggered (if there are remaining retry attempts)
- Compared to the
run()method’s post-check mechanism, this approach is more efficient and precise
§Difference from Synchronous Version
| Feature | run() Sync Version | run_async() Async Version |
|---|---|---|
| Timeout Mechanism | Post-check (check after operation completes) | Real interruption (tokio::time::timeout) |
| Can Interrupt Operation | ❌ Cannot | ✅ Can |
| Timeout Precision | Depends on operation completion | Precise to millisecond level |
| Applicable Scenario | Short synchronous operations | Long asynchronous operations |
§Parameters
operation- Asynchronous operation to execute
§Returns
Returns operation result or error
§Example
use prism3_retry::{RetryBuilder, RetryDelayStrategy, RetryResult};
use std::time::Duration;
#[tokio::main]
async fn main() {
let executor = RetryBuilder::<String>::new()
.set_max_attempts(3)
.set_operation_timeout(Some(Duration::from_secs(5))) // Real timeout interruption
.set_max_duration(Some(Duration::from_secs(30))) // Overall timeout
.set_delay_strategy(RetryDelayStrategy::Fixed {
delay: Duration::from_secs(1)
})
.build();
// Use RetryResult type alias to make code more concise
let result: RetryResult<String> = executor.run_async(|| async {
// Can also use ? operator in async operations, errors will be
// automatically converted
// Example: tokio::fs::read_to_string("file.txt").await?;
tokio::time::sleep(Duration::from_millis(100)).await;
Ok("SUCCESS".to_string())
}).await;
assert!(result.is_ok());
}Sourcepub fn config(&self) -> &RetryBuilder<T, C>
pub fn config(&self) -> &RetryBuilder<T, C>
Get builder configuration