pub trait RetryableWithContext<B: BackoffBuilder, T, E, Ctx, Fut: Future<Output = (Ctx, Result<T, E>)>, FutureFn: FnMut(Ctx) -> Fut> {
// Required method
fn retry(
self,
builder: B,
) -> RetryWithContext<B::Backoff, T, E, Ctx, Fut, FutureFn> ⓘ;
}
Expand description
RetryableWithContext
adds retry support for functions that produce futures with results
and context.
This means all types implementing FnMut(Ctx) -> impl Future<Output = (Ctx, Result<T, E>)>
can use retry
.
Users must provide context to the function and can receive it back after the retry is completed.
§Example
Without context, we might encounter errors such as the following:
error: captured variable cannot escape `FnMut` closure body
--> src/retry.rs:404:27
|
400 | let mut test = Test;
| -------- variable defined here
...
404 | let result = { || async { test.hello().await } }
| - ^^^^^^^^----^^^^^^^^^^^^^^^^
| | | |
| | | variable captured here
| | returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
However, with context support, we can implement it this way:
use anyhow::anyhow;
use anyhow::Result;
use backon::ExponentialBuilder;
use backon::RetryableWithContext;
struct Test;
impl Test {
async fn hello(&mut self) -> Result<usize> {
Err(anyhow!("not retryable"))
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> {
let mut test = Test;
// (Test, Result<usize>)
let (_, result) = {
|mut v: Test| async {
let res = v.hello().await;
(v, res)
}
}
.retry(ExponentialBuilder::default())
.context(test)
.await;
Ok(())
}
Required Methods§
Sourcefn retry(
self,
builder: B,
) -> RetryWithContext<B::Backoff, T, E, Ctx, Fut, FutureFn> ⓘ
fn retry( self, builder: B, ) -> RetryWithContext<B::Backoff, T, E, Ctx, Fut, FutureFn> ⓘ
Generate a new retry