Closed
Description
I believe there's a reason, which I'm not yet familiar with, for why this hasn't been implemented earlier.
My question is: Could there be a Clone
implementation for the structs in mongodb::action::*
?
My primary concern is implementing the following helper trait:
use std::future::{Future, IntoFuture};
use backoff::{exponential::ExponentialBackoff, future::retry, Error as BackoffError, SystemClock};
use mongodb::{
action,
error::{Error as MongoError, ErrorKind},
};
pub trait RetryMongo {
fn retriable<T>(self) -> impl Future<Output = Result<T, MongoError>>
where
Self: Sized + action::Action + Clone + IntoFuture<Output = Result<T, MongoError>>,
{
retry(ExponentialBackoff::<SystemClock>::default(), move || {
let action = self.clone();
async move {
let result: Result<T, MongoError> = action.await;
result.map_err(|e| match e.kind.as_ref() {
ErrorKind::Io(ref io_err) if io_err.kind() == std::io::ErrorKind::TimedOut => {
BackoffError::transient(e)
}
ErrorKind::ServerSelection { .. } => BackoffError::transient(e),
_ => BackoffError::permanent(e),
})
}
})
}
}
impl<T: Send + Sync> RetryMongo for action::Find<'_, T> {}
impl<T: Send + Sync> RetryMongo for action::FindOne<'_, T> {}
impl<T: Send + Sync> RetryMongo for action::FindOneAndDelete<'_, T> {}
impl<T: Send + Sync> RetryMongo for action::FindOneAndReplace<'_, T> {}
impl<T: Send + Sync> RetryMongo for action::FindOneAndUpdate<'_, T> {}
...
let client = Client::with_uri_str("").await.unwrap();
let coll = client.database("").collection::<Document>("");
let result = coll.find(doc! {}).retriable().await;
Currently, this is not achievable with the mongo-rust-driver
since none of the structs implement the Clone trait.
I understand that I could achieve similar behavior by writing a function that accepts a closure and retries the closure directly, but the approach with a trait feels more convenient. It allows for a simple chained call to retriable
, rather than wrapping the entire action.