Skip to content

Question: Is it possible to implement Clone type for mongodb::action::* #1218

Closed
@yourlogarithm

Description

@yourlogarithm

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.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions