Search code examples
multithreadingasynchronousrustrust-dieselrust-axum

Is it safe to `.clone()` Pool of `diesel_async` across threads?


I am using diesel_async.

Let's say I have connections in deadpool. I want total deadpool_max_size connections.

let pool: Pool<AsyncPgConnection> = Pool::builder(deadpool_config)
    .max_size(deadpool_max_size)
    .build()
    .unwrap();

And I have to share the pool across multiple arbitrary number of async threads.

// share the pool with async thread
let _pool = pool.clone();
tokio::spawn(async move { 
    let mut conn = _pool.get().await.unwrap();
    // ... using conn
});

// and another different async thread
let _pool = pool.clone();
tokio::spawn(async move { 
    let mut conn = _pool.get().await.unwrap();
    // ... using conn
});
 
// and so on...
// let _pool = pool.clone(); 
// tokio::spawn(async move { .......

I want the number of connections the entire rust program generates in total must be less than or equal to deadpool_max_size at any time.

In the example above, I didn't wrapped the pool with Arc, Mutex, or RwLock. But just used the pure .clone() directly. The reason was that I saw there's already Arc field in the type.

Is this example suitable to satisfy my intention?


Solution

  • Normally in Rust, if something can't be shared across threads, the compiler will prevent you from doing that.

    In this case, Pool is both Send + Sync, so it is safe to share across threads. It also wraps an Arc internally, so it is cheap to clone and you don't need your own Arc.

    This is even documented:

    This struct can be cloned and transferred across thread boundaries and uses reference counting for its internal state.