1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//
// Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
use snafu::Snafu;
use std::fmt::Debug;
use std::time::Duration;
/// The RetryResult that the operation should return.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum RetryResult<T, E> {
/// Contains the return value if the operation succeed.
Success(T),
/// Contains the error value if duration is exceeded.
Retry(E),
/// Contains an error value to return immediately.
Fail(E),
}
/// An error that the Retry function would give.
#[derive(Debug, PartialEq, Eq, Snafu)]
#[snafu(display(
"Failed after {} retries due to {} which took {:?}",
tries,
error,
total_delay
))]
pub struct RetryError<E: std::fmt::Display> {
/// The error returned by the operation on the last try.
pub error: E,
/// The duration spent waiting between retries of the operation.
pub total_delay: Duration,
/// The total number of times the operation was tried.
pub tries: u64,
}
///
/// Trait which is used check if the Error is Retryable.
///
pub trait Retryable {
fn can_retry(&self) -> bool;
}
///
/// `wrap_with_async_retry!` macro wraps any arbitrary async function with `pravega_rust_client_retry::retry_async::retry_async`
/// This macro takes two parameters. The first parameter is the Retry policy which implements `trait BackoffSchedule`.
/// The second parameter is the async function that needs to be wrapped within the retry logic.
/// The function invocation will be retried only error returned by the function returns `can_retry()` as true.
///
/// E.g: usage
///
/// ```ignore
/// use pravega_rust_client_retry::retry_policy::RetryWithBackoff;
/// use pravega_rust_client_retry::retry_async::retry_async;
/// use pravega_rust_client_retry::wrap_with_async_retry;
/// //CustomError implements Retrayable trait
/// async fn function_a(param1: &str, param2:u8) -> Result<(), CustomError> {
///
/// }
/// let retry_policy = RetryWithBackoff::default_setting().max_tries(10);
/// // the below invocation wraps function_a with the retry logic.
/// wrap_with_async_retry!(retry_policy, function_a("test", 1));
/// ```
///
#[macro_export]
macro_rules! wrap_with_async_retry {
($retrypolicy:expr, $expression:expr) => {
retry_async($retrypolicy, || async {
let r = $expression.await;
match r {
Ok(res) => RetryResult::Success(res),
Err(e) => {
if e.can_retry() {
RetryResult::Retry(e)
} else {
RetryResult::Fail(e)
}
}
}
})
.await
};
}
///
/// `wrap_with_sync_retry!` macro wraps any arbitrary synchronous function with `pravega_rust_client_retry::retry_sync::retry_sync`
/// This macro takes two parameters. The first parameter is the Retry policy which implements `trait BackoffSchedule`.
/// The second parameter is the synchrounous function that needs to be wrapped within the retry logic.
/// The function invocation will be retried only error returned by the function returns `can_retry()` as true.
///
/// E.g: usage
///
/// ```ignore
/// use pravega_rust_client_retry::retry_policy::RetryWithBackoff;
/// use pravega_rust_client_retry::retry_sync::retry_sync;
/// use pravega_rust_client_retry::wrap_with_sync_retry;
/// // CustomError implements Retryable trait
/// fn function_a(param1: &str, param2:u8) -> Result<(), CustomError>{
///
/// }
/// let retry_policy = RetryWithBackoff::default_setting().max_tries(5);
/// // the below invocation wraps function_a with the retry logic.
/// wrap_with_sync_retry!(retry_policy, function_a("test", 1));
/// ```
///
#[macro_export]
macro_rules! wrap_with_sync_retry {
($retrypolicy:expr, $expression:expr) => {
retry_sync($retrypolicy, || {
let r = $expression;
match r {
Ok(res) => RetryResult::Success(res),
Err(e) => {
if e.can_retry() {
RetryResult::Retry(e)
} else {
RetryResult::Fail(e)
}
}
}
})
.await
};
}