Let's say I have a function like below that could fail. The function is also async
async fn can_fail() -> Result<i32, Box<dyn std::error::Error>> {
let mut rng = rand::thread_rng();
let random: u8 = rng.gen();
if random % 2u8 == 0 {
Ok(42)
} else {
Err("error".to_string().into())
}
}
Now I will like to implement a retry
function that can be used to retry a function like can_fail
.
I came up with this in my attempt
fn retry<F: Fn() -> Result<i32, Box<dyn std::error::Error>>>(f: F, retries: i32) -> Result<i32, Box<dyn std::error::Error>>
{
let mut count = 0;
loop {
let result = f();
if result.is_ok() {
break result;
} else {
if count > retries {
break result
}
count += 1;
}
}
}
Then in my attempt to use, I tried to put can_fail
into a closure like this
let my_closure: Box<dyn Fn() -> Result<i32, Box<dyn std::error::Error>>> = Box::new(|| {
can_fail().await
});
But this fails with the error
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> src/main.rs:208:19
|
207 | let my_closure: Box<dyn Fn() -> Result<i32, Box<dyn std::error::Error>>> = Box::new(|| {
| -- this is not `async`
208 | can_fail().await
| ^^^^^^ only allowed inside `async` functions and blocks
So I am kinda stuck. So my question are:
retry
I came up with do the job? I cannot tell as I cannot even pass in a closure to itawait
is only allowed inside async
functions and blocks` error in this scenario?Your retry()
function looks OK, but to pass an async function into it you need to fix it to accept a function returning Future
, and to be able to .await
it, make it async:
async fn retry_async<Fut, F: Fn() -> Fut>(f: F, retries: i32) -> Result<i32, Box<dyn std::error::Error>>
where
Fut: Future<Output = Result<i32, Box<dyn std::error::Error>>>,
{
let mut count = 0;
loop {
let result = f().await;
if result.is_ok() {
break result;
} else {
if count > retries {
break result;
}
count += 1;
}
}
}
retry(can_fail, 3).await.expect("failed to many times");
You can also make the function more generic by:
FnMut
instead of Fn
.async fn retry_async<T, E, Fut, F: FnMut() -> Fut>(mut f: F, retries: i32) -> Result<T, E>
where
Fut: Future<Output = Result<T, E>>,
{
let mut count = 0;
loop {
let result = f().await;
if result.is_ok() {
break result;
} else {
if count > retries {
break result;
}
count += 1;
}
}
}