Connection Pool
Recipe | Crates | Categories |
---|---|---|
Create a Connection Pool |
Create a Connection Pool
deadpool
⮳ is a simple async pool for connections and objects of any type.
//! This example demonstrates how to use the `deadpool` crate to manage a pool //! of connections. //! //! The `deadpool` crate provides a generic connection pool implementation that //! can be used with any type that implements the `managed::Manager` trait. //! //! In this example, we create a simple `Server` type that represents a //! connection to a server. The `Manager` type is responsible for creating and //! recycling `Server` instances. use deadpool::managed; #[derive(Debug)] enum Error { Fail, // Represents a failure in the connection or manager. } struct Server; impl Server { // Represents a connection to a server. async fn get_answer(&self) -> i32 { 42 } } struct Manager; // The `Manager` is responsible for creating and recycling `Server` instances. impl managed::Manager for Manager { type Error = Error; type Type = Server; /// Creates a new `Server` instance. async fn create(&self) -> Result<Server, Error> { Ok(Server) // In a real-world scenario, this would establish a connection. } async fn recycle( &self, _: &mut Server, _: &managed::Metrics, ) -> managed::RecycleResult<Error> { Ok(()) } } // Type alias for the connection pool. type Pool = managed::Pool<Manager>; #[tokio::main] async fn main() -> anyhow::Result<()> { let mgr = Manager; // Create a new connection pool with the given manager. let pool = Pool::builder(mgr).build()?; // Get a connection from the pool. let conn = pool.get().await.map_err(|err| { anyhow::anyhow!("Could not retrieve from the Pool: {:?}", err) })?; let answer = conn.get_answer().await; assert_eq!(answer, 42); println!("The answer is {}", answer); Ok(()) }
Here is an example demonstrating the use of deadpool
⮳ to connect to a Postgres database:
//! This example demonstrates how to use `deadpool-postgres` to manage a pool of //! PostgreSQL connections. //! `deadpool` is an async pool for connections and objects of any type. //! `deadpool_postgres` implements a `deadpool` manager for `tokio-postgres` //! and also provides a statement cache by wrapping `tokio_postgres::Client` and //! `tokio_postgres::Transaction`. //! //! Add to your `Config.toml`: //! deadpool = "0.12.1" # or latest version //! deadpool-postgres = { version = "0.14.1", features = ["serde"] } //! //! Add you database's configuration to your `.env` file, for example: //! PG__HOST=pg.example.com //! PG__USER=john_doe //! PG__PASSWORD=topsecret //! PG__DBNAME=example //! PG__POOL__MAX_SIZE=16 //! PG__POOL__TIMEOUTS__WAIT__SECS=5 //! PG__POOL__TIMEOUTS__WAIT__NANOS=0 use deadpool_postgres::Runtime; use dotenvy::dotenv; use tokio_postgres::NoTls; /// Configuration for the application. #[derive(Debug, serde::Deserialize)] struct Config { pub pg: deadpool_postgres::Config, } impl Config { // With the `serde` feature enabled, we can read the configuration using the // `config` crate. 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() -> anyhow::Result<()> { // Loads the `.env` file from the current directory or parents. dotenv().ok(); // Hydrate the configuration from environment variables. let cfg = Config::from_env()?; // Creates a new `Pool` using the `deadpool_postgres::Config`. let pool = cfg.pg.create_pool(Some(Runtime::Tokio1), NoTls)?; // Retrieves an Object from this Pool or waits for one to become available let client = pool.get().await?; // Like `tokio_postgres::Client::prepare()`, but uses an existing // `Statement` from the `StatementCache` if possible let stmt = client.prepare_cached("SELECT version()").await?; let rows = client.query(&stmt, &[]).await?; for row in rows { let version: &str = row.get(0); println!("PostgreSQL version: {}", version); } Ok(()) }