Trait backon::RetryableWithContext
source · 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) -> Retry<B::Backoff, T, E, Ctx, Fut, FutureFn>;
}
Expand description
RetryableWithContext will add retry support for functions that produces a futures with results and context.
That means all types that implement FnMut(Ctx) -> impl Future<Output = (Ctx, Result<T, E>)>
will be able to use retry
.
This will allow users to pass a context to the function and return it back while retry finish.
§Example
Without context, we could meet errors like 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
But with context support, we can implement in 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(())
}