Search code examples
multithreadingrustactix-webrust-diesel

web::block() fails with "`NonNull<pq_sys::pg_conn>` cannot be shared between threads safely"


#[macro_use]
extern crate diesel;

use diesel::result::Error;

use actix_web::web;
use diesel::{PgConnection, QueryDsl, RunQueryDsl};
use r2d2::{Pool, PooledConnection};
use r2d2_diesel::ConnectionManager;
use schema::tests::dsl::*;

pub mod schema;

pub type MyDBConnectionManager = ConnectionManager<PgConnection>;
pub type MyPool = Pool<MyDBConnectionManager>;
pub type MyDBConnection = PooledConnection<MyDBConnectionManager>;

struct S { }

impl S {
    async fn download_and_store_object(pool: web::Data<MyPool>) -> Result<(), Error>
    {
        let conn_ = pool.get().expect("couldn't get db connection from pool");
        let conn = &conn_;

        let v_data_size: Option<i64> = web::block(move || -> Result<_, Error> {
            Ok(tests.select(b).get_result::<Option<i64>>(&**conn)?)
        }).await.unwrap();

        Ok(())

    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    Ok(())
}
`NonNull<pq_sys::pg_conn>` cannot be shared between threads safely
within `PooledConnection<ConnectionManager<PgConnection>>`, the trait `Sync` is not implemented for `NonNull<pq_sys::pg_conn>`
required because of the requirements on the impl of `std::marker::Send` for `&PooledConnection<ConnectionManager<PgConnection>>`
required because it appears within the type `[closure@src/main.rs:26:51: 28:10]`rustcE0277

Schema:

table! {
    tests (seq) {
        seq -> Int4,
        a -> Nullable<Bytea>,
        b -> Nullable<Int8>,
    }
}

What is the error? And how to correct it?


Solution

  • As said in the comments, Conn can not be shared between threads, so in this case you would need to move the Pool handle, and get a connection from within the clusure itself:

    #[macro_use]
    extern crate diesel;
    
    use diesel::result::Error;
    
    use actix_web::web;
    use diesel::{PgConnection, QueryDsl, RunQueryDsl};
    use r2d2::{Pool, PooledConnection};
    use r2d2_diesel::ConnectionManager;
    use schema::tests::dsl::*;
    
    pub mod schema;
    
    pub type MyDBConnectionManager = ConnectionManager<PgConnection>;
    pub type MyPool = Pool<MyDBConnectionManager>;
    pub type MyDBConnection = PooledConnection<MyDBConnectionManager>;
    
    struct S { }
    
    impl S {
        async fn download_and_store_object(pool: web::Data<MyPool>) -> Result<(), Error>
        {
    
            let v_data_size: Option<i64> = web::block(move || -> Result<_, Error> {
                let conn = pool.get().expect("couldn't get db connection from pool");
    
                Ok(tests.select(b).get_result::<Option<i64>>(&conn)?)
            }).await.unwrap();
    
            Ok(())
    
        }
    }