0

I have to retry an async function- handle_message & I'm using the retry crate for it (version "1.2.1"). But the second argument is a closure.

use retry::{retry, delay::Fixed};

retry(Fixed::from_millis(10000).take(3), || async {
    let message = handle_message(my_message.clone()).await;

    match message {
        Ok(()) => info!("Message successfully registered"),
        Err(e) => {
            // For certain errors likely to resolve if we wait a bit, we schedule a retry
            if e.is_code(EC::MyErrorCode, true)
            {
                debug!("Handling message error- {:?}", e);
                return Err(format!("Dkg message w/ error: {:?}", e));
            }
        }
    }

    Ok(()) // Don't try any other errors
});

I'm getting the following error:

the trait bound `OperationResult<_, _>: From<[async block@src/my_file.rs:xx:xx]>` is not satisfied
the trait `From<std::result::Result<T, E>>` is implemented for `OperationResult<T, E>`
required for `[async block@src/my_file.rs:xx:xx]` to implement `Into<OperationResult<_, _>>`

I tried return from the async closure OperationResult::Ok/Err as well instead Result::Ok/Err but I still get the same error.

Is it even possible to use an async function inside the retry block?

NewToCode
  • 174
  • 8
  • retry doesn't support async funcitons. You will have to find some other crate for that or write something yourself (which shouldn't be that hard). – Aleksander Krauze Aug 09 '23 at 08:22
  • You could wrap your async block in a call to some async runtime/executor that blocks the current thread while polling the future, like [`futures::executor::block_on`](https://docs.rs/futures/latest/futures/executor/fn.block_on.html), for example. – Jonas Fassbender Aug 09 '23 at 09:26

1 Answers1

0

As you may see in the source code, retry crate doesn't handle async futures. Another one, tryhard does though. Check the custom_backoff method:

use std::time::Duration;
use tryhard::RetryPolicy;

tryhard::retry_fn(|| read_file("Cargo.toml"))
    .retries(10)
    .custom_backoff(|attempt, error: &std::io::Error| {
        if error.to_string().contains("foobar") {
            // returning this will cancel the loop and
            // return the most recent error
            RetryPolicy::Break
        } else {
            RetryPolicy::Delay(Duration::from_millis(50))
        }
    })
    .await?;

If migration is too much for you, try to de-asyncify the call, blocking the current thread. An inspiring example for tokio, which possibly should be wrapped with spawn_blocking to drive IO forward:

let message = tokio::runtime::Handle::current().block_on(
  handle_message(my_message.clone())
);
xamgore
  • 1,723
  • 1
  • 15
  • 30