If it fails, I want to call it again after 15 seconds, repeat 4 times, and only if by then I still have an error, return the error. Something like:
fn try_four_times(args) -> anyhow::Result<String>{
for _try in 1..4 {
match fetch_some_data(args) {
Ok(json) => return Ok(json),
Err(some_error) => {
// retry, but how?
},
}
thread::sleep(time::Duration::from_secs(15);
}
// after having tried four times
Err(the_error_that_previously_appeared)
}
I don't even know how to ask Duckduckgo, what are the keywords I am missing here?
It looks like your goal is to get some_error out from the final of four match arms in the for loop. You could put an if _try >= 4 { return Err(some_error) } else { continue } in place of the // retry, but how? line. Then that will pass until it hits the return limit.
Side note: I also think you might be looking for 1..=4 or 0..4 on the range.
fn try_four_times(args: Args) -> anyhow::Result<String>{
let mut result;
for _ in 1..4 {
result = fetch_some_data(args);
if result.is_ok(){
break;
}
thread::sleep(time::Duration::from_secs(15);
}
// after having tried four times
result
}
fn try_n_times(args: Args, n: usize) -> anyhow::Result<String> {
for _ in 0..n - 1 {
let result = fetch_some_data(args);
if result.is_ok() {
return result;
}
}
fetch_some_data(args)
}
The recursive one does indeed read somewhat more naturally:
fn try_n_times(args: Args, n: usize) -> anyhow::Result<String> {
let result = fetch_some_data(args);
if n <= 1 || result.is_ok() {
result
} else {
try_n_times(args, n - 1)
}
}
fn try_four_times(args: Args) -> anyhow::Result<String> {
// Make this as complicated as you like
let try_get_data = move || fetch_some_data(args);
std::iter::from_fn(|| Some(try_get_data()))
.inspect(|r| if r.is_err() {
thread::sleep(time::Duration::from_secs(15));
})
.take(3)
.find(Result::is_ok)
.unwrap_or_else(try_get_data)
}
So now DRY means you are not supposed to call functions more than once? I don't think so. Functions are meant for abstracting away repetitive pieces of code (among others), exactly so that you can call them as many times as you please, without needing to copy-paste.
I don't see how that's obfuscated in any way – it's a perfectly idiomatic iterator chain. Please let's not start the pointless "iterators are hard to read" debate again, it's not productive.
Thank you so much for you answers. I've been having fun with my mentor's idea of a recursive function and I've come up with … wait I wanted your help, the compiler told me to remove a semicolon and now… I've got different, more interesting errors.
Cheers for the solution with iterators. BTW we really need this obfuscated rust blog!
If it were me I would separate out the mechanics of making a single request from the recursive mechanics of making retries with timeouts. Have a function to make the single request, and cal it from the recursive retry function. As raggy indicates with the recursive example above.