ihrwein / backoff

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

Async version seems to ignore BackoffError::Permanent as permanent error and retries anyway #18

Closed nazar-pc closed 4 years ago

nazar-pc commented 4 years ago

I have a piece of code that essentially does something like this:

let download_fn = || async {
    Err(backoff::Error::Permanent(()))
};
let result = download_fn.retry(ExponentialBackoff::default()).await;

I have observed that this causes retry to retry multiple times even though error is clearly defined as permanent.

nazar-pc commented 4 years ago

Interesting, example above is not 100% correct. In my case ? operator caused Error::Permanent(..) to be wrapped into Error::Transient(Error::Permanent(..)), which is surprising.

The reason of that was type inference caused by this piece of code:

let result: Result<Data, DownloadError> = download_fn
    .retry({
        let mut backoff = ExponentialBackoff::default();
        backoff.max_elapsed_time = Some(MAX_BACKOFF_ELAPSED_TIME);
        backoff
    })
    .await
    .map_err(|error| match error {
        BackoffError::Transient(error) | BackoffError::Permanent(error) => error,
    });

Removing map_err solved the issue, hopefully this helps someone.