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 escapeHowever, 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