backon

Trait 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,
    ) -> 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§

Source

fn retry( self, builder: B, ) -> RetryWithContext<B::Backoff, T, E, Ctx, Fut, FutureFn>

Generate a new retry

Implementors§

Source§

impl<B, T, E, Ctx, Fut, FutureFn> RetryableWithContext<B, T, E, Ctx, Fut, FutureFn> for FutureFn
where B: BackoffBuilder, Fut: Future<Output = (Ctx, Result<T, E>)>, FutureFn: FnMut(Ctx) -> Fut,