如何在 Rust 的重试中使用异步闭包

How to use an async closure in Rust's retry

提问人:NewToCode 提问时间:8/9/2023 更新时间:8/9/2023 访问量:91

问:

我必须重试一个异步函数 - 并且我正在使用它的重试 crate(版本“1.2.1”)。但第二个论点是结束。handle_message

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
});

我收到以下错误:

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<_, _>>`

我也尝试从异步闭包返回,但我仍然收到同样的错误。OperationResult::Ok/ErrResult::Ok/Err

是否可以在重试块中使用异步函数?

异步 rust 作用域 闭包 retry-logic

评论

0赞 Aleksander Krauze 8/9/2023
重试不支持异步功能。你将不得不为此找到一些其他的板条箱,或者自己写一些东西(这应该不难)。
0赞 Jonas Fassbender 8/9/2023
你可以将你的异步块包装在对某个异步运行时/执行器的调用中,该运行时/执行器在轮询未来时阻止当前线程,例如 futures::executor::block_on

答:

0赞 xamgore 8/9/2023 #1

正如您在源代码中看到的那样,retry crate 不处理异步 futures。另一个,tryhard做到了。检查custom_backoff方法:

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?;

如果迁移对你来说太多了,请尝试取消异步调用,阻止当前线程。对于 tokio 来说,这是一个鼓舞人心的例子,它可能应该用 spawn_blocking 来推动 IO 向前发展:

let message = tokio::runtime::Handle::current().block_on(
  handle_message(my_message.clone())
);