ihrwein / backoff

Exponential backoff and retry for Rust.
https://github.com/ihrwein/backoff
Apache License 2.0
306 stars 37 forks source link

Error while trying to combine backoff::error with async #22

Closed chkeita closed 3 years ago

chkeita commented 4 years ago

I am trying to add a retry logic to reqwest::RequestBuilder by extending it with trait.

#[async_trait]
pub trait SendRetry {
    async fn send_retry(
        self,
        retry_period: Duration,
        max_elapsed_time: Duration,
    ) -> Result<Response>;
}

#[async_trait]
impl SendRetry for reqwest::RequestBuilder {
    async fn send_retry(
        self,
        retry_period: Duration,
        max_elapsed_time: Duration,
    ) -> Result<Response> {

        let op = || async {
            let cloned = self
                .try_clone()
                .ok_or(backoff::Error::Permanent(anyhow::Error::msg("this request cannot be cloned")))?;

            let response = 
            cloned.send().await
            .map_err(|err| backoff::Error::Transient(anyhow::Error::from(err)))?;
            Ok(response)
        };

        let result = op
            .retry(ExponentialBackoff {
                current_interval: retry_period,
                initial_interval: retry_period,
                max_elapsed_time: Some(max_elapsed_time),
                ..ExponentialBackoff::default()
            })
            .await?;

        Ok(result)
    }
}

but i get the following exception

error[E0698]: type inside `async fn` body must be known in this context
  --> utils\src\lib.rs:47:14
   |
47 |             .retry(ExponentialBackoff {
   |              ^^^^^ cannot infer type for type parameter `E`
   |
note: the type is part of the `async fn` body because of this `await`
  --> utils\src\lib.rs:46:22
   |
46 |           let result = op
   |  ______________________^
47 | |             .retry(ExponentialBackoff {
48 | |                 current_interval: retry_period,
49 | |                 initial_interval: retry_period,
...  |
52 | |             })
53 | |             .await?;
   | |__________________^

Any idea how to fix this ?

ihrwein commented 3 years ago

Thanks @chkeita for reporting this issue. I couldn't reproduce it with the master branch. I made your example into a whole crate, you can check it out here: https://github.com/ihrwein/backoff-issue-22/blob/main/src/lib.rs Please close the issue if you also managed to compile the code. Thank you.

Edit: posting the example here for completeness:

extern crate backoff;

use backoff::ExponentialBackoff;
use std::time::Duration;

use anyhow::Result;
use reqwest::Response;

#[macro_use]
extern crate async_trait;

#[async_trait]
pub trait SendRetry {
    async fn send_retry(
        self,
        retry_period: Duration,
        max_elapsed_time: Duration,
    ) -> Result<Response>;
}

#[async_trait]
impl SendRetry for reqwest::RequestBuilder {
    async fn send_retry(
        self,
        retry_period: Duration,
        max_elapsed_time: Duration,
    ) -> Result<Response> {
        let op = || async {
            self.try_clone()
                .ok_or(backoff::Error::Permanent(anyhow::Error::msg(
                    "this request cannot be cloned",
                )))?
                .send()
                .await
                .map_err(|err| backoff::Error::Transient(anyhow::Error::from(err)))
        };

        backoff::tokio::retry(
            ExponentialBackoff {
                current_interval: retry_period,
                initial_interval: retry_period,
                max_elapsed_time: Some(max_elapsed_time),
                ..ExponentialBackoff::default()
            },
            op,
        )
        .await
    }
}
ihrwein commented 3 years ago

Closing due to inactivity.