Crates.io | retrying |
lib.rs | retrying |
version | 0.1.0 |
source | src |
created_at | 2023-12-19 15:58:34.08927 |
updated_at | 2023-12-19 15:58:34.08927 |
description | General-purpose retrying library for Rust with macros and functions |
homepage | https://github.com/dintegrity/retrying |
repository | |
max_upload_size | |
id | 1074430 |
size | 54,973 |
General-purpose retrying library, written in Rust, to simplify the task of adding retry behavior to rust functions.
Support sync and async (tokio, async-std) functions.
[dependencies]
retrying = "0.1.0"
The main public interface in retrying is retrying::retry
macros.
#[retrying::retry]
fn my_function(){}
This macros has a lot of configuration options and allows developers to write fault tolerant functions without thinking about implementation of retry functionality.
:warning: The macros generates code and adds variables with prefix retrying_
into code. To avoid variable conflicts please don't use variables with this prefix in functions with retry
macros.
This section describes configuration options that specify when method execution should stop retrying.
Config option | OS Environments | Default | Description |
---|---|---|---|
stop=attempts(u32 ) |
{PREFIX}__RETRYING__STOP__ATTEMPTS | - | Number of retries |
stop=delay(f32 ) |
{PREFIX}__RETRYING__STOP__DELAY | - | Retrying period (seconds) |
It is possible to combine several stop conditions by using the or operator(|
) operator. For example, configuration
#[retrying::retry(stop=(attempts(10)|delay(60.8)))]
fn my_function(){}
means the function should retry 10 times but doesn't make new attempt after 60 seconds.
If stop configuration is not specified then retry macros makes new attempts until function be finished without Err.
This section describes configuration options that specify delay between each attempt.
Config option | OS Environments | Default | Description |
---|---|---|---|
wait=fixed(f32 ) |
{PREFIX}__RETRYING__WAIT__FIXED | 0 | Number of seconds between retries |
wait=random(min=f32 , max=f32 ) |
{PREFIX}__RETRYING__WAIT__RANDOM__(MIN|MAX) | min=0,max=3600 | Randomly wait min to max seconds between retries |
wait=exponential(multiplier=f32 , min=f32 , max=f32 , exp_base=u32 ) |
{PREFIX}__RETRYING__WAIT__EXPONENTIAL__(MULTIPLIER|MIN|MAX|EXP_BASE) | multiplier=1, min=0, max=3600, exp_base=2 | Wait multiplier * exp_base^(num of retry - 1) + min seconds between each retry starting with min seconds, then up to max seconds, then max seconds afterwards |
Using only one wait option is possible.
This section describes configuration options that specify retrying conditions.
Config option | OS Environments | Default | Description |
---|---|---|---|
retry=if_errors(error_1, error_2, error_2) | Not applicable | - | Retry only on specific errors |
retry=if_not_errors(error_1, error_2, error_3) | Not applicable | - | Don't retry on specific errors |
Using only one retry option is possible.
There are certain list of use cases when retry configuration requires updating configuration values in runtime. For example, It is useful when we need a different number of attempts per environment (dev, prod, stage), systems, unit tests etc.
Retrying allows overriding macros configuration in runtime using env variables with special configuration option envs_prefix
like
#[retrying::retry(<retry configurations>,envs_prefix="test")]
:warning: Limitations
stop=attempts(1))
is not defined in macros code then the OS env variable {PREFIX}__RETRYING__STOP__ATTEMPTS
doesn't affect code execution. In other words, the OS environment variable can override only the value of the configured option and it is not able to change the option itself.Example of usage:
#[retrying::retry(stop=attempts(2),envs_prefix="test")]
With above configuration macros checks in runtime the availability of OS env variable TEST__RETRYING__STOP__ATTEMPTS (case-insensitive) and if variable is set then number of retry attempt will be the value of TEST__RETRYING__STOP__ATTEMPTS. If the list of OS environment contains more than one configuration option with the same prefix then macros ignores OS env variable and take configuration value from code.
tokio
- builds retrying library for using with tokio asynchronous runtime.
async_std
- builds retrying library for using with async_std asynchronous runtime.
Examples are available in ./crates/retrying/example and can be tested using cargo. Sync:
cargo run --example sync
Async tokio:
cargo run --features="tokio" --example tokio
Async async-std:
cargo run --features="async_std" --example async_std
retrying::retry
macros is not a magic and it only helps developers to avoid writing extra code.
The resulting code depends on the provided configuration and may be changed in future releases.
Examples of code generation:
#[retry(stop=(attempts(4)|duration(2)),wait=fixed(0.9))]
fn my_method(in_param: &str) -> Result<i32, ParseIntError> {
in_param.parse::<i32>()
}
Generated code:
fn my_method(in_param: &str) -> Result<i32, ParseIntError> {
let mut retrying_context = ::retrying::RetryingContext::new();
use ::retrying::stop::Stop;
let retrying_stop =
::retrying::stop::StopAttemptsOrDuration::new(4u32, 2f32);
use ::retrying::wait::Wait;
let retrying_wait = ::retrying::wait::WaitFixed::new(0.9f32);
loop {
match { in_param.parse::<i32>() } {
Ok(result) => return Ok(result),
Err(err) if !retrying_stop.stop_execution(&retrying_context) => {
match err {
std::num::ParseIntError { .. } => (),
_ => break Err(err),
};
retrying_context.add_attempt();
::retrying::sleep_sync(retrying_wait.wait_duration(&retrying_context));
}
Err(err) => break Err(err),
}
}
}
It is possible to use cargo for checking generated code. For examples, below command shows generated code for all examples,
cd ./crates/retrying
cargo rustc --profile=check --examples -- -Zunpretty=expanded