simple_pg_pool

Crates.iosimple_pg_pool
lib.rssimple_pg_pool
version0.16.1
sourcesrc
created_at2024-01-08 18:32:36.56956
updated_at2024-05-02 17:05:19.903102
descriptionDead simple async pool for tokio-postgres
homepage
repository
max_upload_size
id1092854
size92,761
Thomas Dagenais (exrok)

documentation

README

simple_pg_pool

Fork of deadpool-postgres for deeper integration into the simple_pg project.

Primary Goals:

  • Deeply integrate with a SQL query builder.
  • Unify client types so generic client isn't needed. Replaced by impl Deref<Conn>.
  • Provided methods for fast & parallel unit testing via schema universes.
  • Optimize performance for our use cases.
  • Reduce incremental compile times via reducing monomorphization.

Features

Feature Description Extra dependencies Default
rt_tokio_1 Enable support for tokio crate deadpool/rt_tokio_1 yes
rt_async-std_1 Enable support for async-std crate deadpool/rt_async-std_1 no
serde Enable support for serde crate deadpool/serde, serde/derive no

Important: async-std support is currently limited to the async-std specific timeout function. You still need to enable the tokio1 feature of async-std in order to use this crate with async-std.

Example

The following example assumes a PostgreSQL reachable via an unix domain socket and peer auth enabled for the local user in pg_hba.conf. If you're running Windows you probably want to specify the host, user and password in the connection config or use an alternative authentication method.

use simple_pg_pool::{Config, Manager, ManagerConfig, Pool, RecyclingMethod, Runtime};
use simple_pg_client::NoTls;

#[tokio::main]
async fn main() {
    let mut cfg = Config::new();
    cfg.dbname = Some("deadpool".to_string());
    cfg.manager = Some(ManagerConfig { recycling_method: RecyclingMethod::Fast });
    let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
    for i in 1..10 {
        let mut client = pool.get().await.unwrap();
        let stmt = client.prepare_cached("SELECT 1 + $1").await.unwrap();
        let rows = client.query(&stmt, &[&i]).await.unwrap();
        let value: i32 = rows[0].get(0);
        assert_eq!(value, i + 1);
    }
}

Example with config and dotenv crate

# .env
PG__DBNAME=deadpool
use simple_pg_pool::{Manager, Pool, Runtime};
use dotenv::dotenv;
# use serde_1 as serde;
use simple_pg_client::NoTls;

#[derive(Debug, serde::Deserialize)]
# #[serde(crate = "serde_1")]
struct Config {
    pg: simple_pg_pool::Config
}

impl Config {
    pub fn from_env() -> Result<Self, config::ConfigError> {
        config::Config::builder()
           .add_source(config::Environment::default().separator("__"))
           .build()?
           .try_deserialize()
    }
}

#[tokio::main]
async fn main() {
    dotenv().ok();
    let mut cfg = Config::from_env().unwrap();
    let pool = cfg.pg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
    for i in 1..10 {
        let mut client = pool.get().await.unwrap();
        let stmt = client.prepare_cached("SELECT 1 + $1").await.unwrap();
        let rows = client.query(&stmt, &[&i]).await.unwrap();
        let value: i32 = rows[0].get(0);
        assert_eq!(value, i + 1);
    }
}

Note: The code above uses the crate name config_crate because of the config feature and both features and dependencies share the same namespace. In your own code you will probably want to use ::config::ConfigError and ::config::Config instead.

Example using an existing simple_pg_client::Config object

use std::env;
use simple_pg_pool::{Manager, ManagerConfig, Pool, RecyclingMethod};
use simple_pg_client::NoTls;

#[tokio::main]
async fn main() {
    let mut pg_config = simple_pg_client::Config::new();
    pg_config.host_path("/run/postgresql");
    pg_config.host_path("/tmp");
    pg_config.user(env::var("USER").unwrap().as_str());
    pg_config.dbname("deadpool");
    let mgr_config = ManagerConfig {
        recycling_method: RecyclingMethod::Fast
    };
    let mgr = Manager::from_config(pg_config, NoTls, mgr_config);
    let pool = Pool::builder(mgr).max_size(16).build().unwrap();
    for i in 1..10 {
        let mut client = pool.get().await.unwrap();
        let stmt = client.prepare_cached("SELECT 1 + $1").await.unwrap();
        let rows = client.query(&stmt, &[&i]).await.unwrap();
        let value: i32 = rows[0].get(0);
        assert_eq!(value, i + 1);
    }
}

FAQ

  • The database is unreachable. Why does the pool creation not fail?

    Deadpool has identical startup and runtime behaviour and therefore the pool creation will never fail.

    If you want your application to crash on startup if no database connection can be established just call pool.get().await right after creating the pool.

  • Why are connections retrieved from the pool sometimes unuseable?

    In deadpool-postgres 0.5.5 a new recycling method was implemented which is the default since 0.8. With that recycling method the manager no longer performs a test query prior returning the connection but relies solely on simple_pg_client::Client::is_closed instead. Under some rare circumstances (e.g. unreliable networks) this can lead to simple_pg_client not noticing a disconnect and reporting the connection as useable.

    The old and slightly slower recycling method can be enabled by setting ManagerConfig::recycling_method to RecyclingMethod::Verified or when using the config crate by setting PG__MANAGER__RECYCLING_METHOD=Verified.

  • How can I enable features of the tokio-postgres crate?

    Make sure that you depend on the same version of tokio-postgres as deadpool-postgres does and enable the needed features in your own Crate.toml file:

    [dependencies]
    deadpool-postgres = { version = "0.9" }
    tokio-postgres = { version = "0.7", features = ["with-uuid-0_8"] }
    

    Important: The version numbers of deadpool-postgres and tokio-postgres do not necessarily match. If they do it is just a coincidence that both crates have the same MAJOR and MINOR version number.

    deadpool-postgres tokio-postgres
    0.7 – 0.12 0.7
    0.6 0.6
    0.4 – 0.5 0.5
    0.2 – 0.3 0.5.0-alpha
  • How can I clear the statement cache?

    You can call pool.manager().statement_cache.clear() to clear all statement caches or pool.manager().statement_cache.remove() to remove a single statement from all caches.

    Important: The ClientWrapper also provides a statement_cache field which has clear() and remove() methods which only affect a single client.

License

Licensed under either of

at your option.

Commit count: 0

cargo fmt