I have a function fetch_stuff
that needs a mutable ref to a sqlx connection. I would like to retry this function up to N times if it fails. I need this retry behavior for many similar functions so I tried to make a generic retry_up_to_n_times
func, that takes an async fnmut and the number of retries allowed as input.
#[derive(Clone)]
pub struct App {
db_pool: sqlx::PgPool,
}
impl App {
pub async fn foo(&self) {
let mut db_conn = self.db_pool.acquire().await.unwrap();
retry_up_to_n_times(|| fetch_stuff(&mut db_conn), 3).await;
}
}
pub async fn fetch_stuff(db_conn: &mut sqlx::postgres::PgConnection) -> Result<(), StorageError> {
//do stuff with db_conn
Ok(())
}
pub async fn retry_up_to_n_times<F, T, O, E>(mut func: F, max_tries: usize) -> T::Output
where
F: FnMut() -> T,
T: std::future::Future<Output = Result<O, E>>,
E: Error
{
let mut fail_count = 0;
loop {
match func().await {
Ok(t) => return Ok(t),
Err(e) => {
fail_count += 1;
if fail_count >= max_tries {
return Err(e);
}
}
}
}
}
The compiler gives me this error
error: captured variable cannot escape `FnMut` closure body
--> src/app/tag.rs:32:32
|
31 | let mut db_conn = self.db_pool.acquire().await.unwrap();
| ----------- variable defined here
32 | retry_up_to_n_times(|| fetch_stuff(&mut db_conn), 3).await;
| - ^^^^^^^^^^^^^^^^^-------^
| | | |
| | | variable captured here
| | returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
I don't have much experience with rust so I'm not sure I understand it fully. I've read all I could find on the subject and I tried playing with Rc and RefCell, without success. I also tried using tokio_retry, but ended up with the same issue.
Is what I'm trying to do even possible ?