diesel

Module r2d2

Source
Available on crate feature r2d2 only.
Expand description

Connection pooling via r2d2.

Note: This module requires enabling the r2d2 feature

§Example

The below snippet is a contrived example emulating a web application, where one would first initialize the pool in the main() function (at the start of a long-running process). One would then pass this pool struct around as shared state, which, here, we’ve emulated using threads instead of routes.

use diesel::prelude::*;
use diesel::r2d2::ConnectionManager;
use diesel::r2d2::Pool;
use diesel::result::Error;
use std::thread;


pub fn get_connection_pool() -> Pool<ConnectionManager<DbConnection>> {
    let url = database_url_for_env();
    let manager = ConnectionManager::<DbConnection>::new(url);
    // Refer to the `r2d2` documentation for more methods to use
    // when building a connection pool
    Pool::builder()
        .test_on_check_out(true)
        .build(manager)
        .expect("Could not build connection pool")
}

pub fn create_user(conn: &mut DbConnection, user_name: &str) -> Result<usize, Error> {
    use schema::users::dsl::*;

    diesel::insert_into(users)
        .values(name.eq(user_name))
        .execute(conn)
}

fn main() {
    let pool = get_connection_pool();
    let mut threads = vec![];
    let max_users_to_create = 1;

    for i in 0..max_users_to_create {
        let pool = pool.clone();
        threads.push(thread::spawn({
            move || {
                let conn = &mut pool.get().unwrap();
                let name = format!("Person {}", i);
                create_user(conn, &name).unwrap();
            }
        }))
    }

    for handle in threads {
        handle.join().unwrap();
    }
}

§A note on error handling

When used inside a pool, if an individual connection becomes broken (as determined by the R2D2Connection::is_broken method) then, when the connection goes out of scope, r2d2 will close and return the connection to the DB.

diesel determines broken connections by whether or not the current thread is panicking or if individual Connection structs are broken (determined by the is_broken() method). Generically, these are left to individual backends to implement themselves.

For SQLite, PG, and MySQL backends is_broken() is determined by whether or not the TransactionManagerStatus (as a part of the AnsiTransactionManager struct) is in an InError state or contains an open transaction when the connection goes out of scope.

§Testing with connections pools

When testing with connection pools, it is recommended to set the pool size to 1, and use a customizer to ensure that the transactions are never committed. The tests using a pool prepared this way can be run in parallel, because the changes are never committed to the database and are local to each test.

§Example

use diesel::prelude::*;
use diesel::r2d2::ConnectionManager;
use diesel::r2d2::CustomizeConnection;
use diesel::r2d2::TestCustomizer;
use diesel::r2d2::Pool;
use diesel::result::Error;
use std::thread;


pub fn get_testing_pool() -> Pool<ConnectionManager<DbConnection>> {
    let url = database_url_for_env();
    let manager = ConnectionManager::<DbConnection>::new(url);

    Pool::builder()
        .test_on_check_out(true)
        .max_size(1) // Max pool size set to 1
        .connection_customizer(Box::new(TestCustomizer)) // Test customizer
        .build(manager)
        .expect("Could not build connection pool")
}

table! {
    users {
        id -> Integer,
        name -> Text,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_1() {
        let pool = get_testing_pool();
        let mut conn = pool.get().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
        )
        .execute(&mut conn)
        .unwrap();

        crate::insert_into(users::table)
            .values(users::name.eq("John"))
            .execute(&mut conn)
            .unwrap();
    }

    #[test]
    fn test_2() {
        let pool = get_testing_pool();
        let mut conn = pool.get().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
        )
        .execute(&mut conn)
        .unwrap();

        let user_count = users::table.count().get_result::<i64>(&mut conn).unwrap();
        assert_eq!(user_count, 0); // Because the transaction from test_1 was never committed
    }
}

Modules§

  • Event subscriptions.

Structs§

Enums§

  • The error used when managing connections with r2d2.

Traits§

  • A trait which allows for customization of connections.
  • A trait which handles errors reported by the ManageConnection.
  • A trait which is provided with information about events in a connection pool.
  • A trait which provides connection-specific functionality.
  • A trait indicating a connection could be used inside a r2d2 pool

Type Aliases§