I used r2d2_postgres to create a connection pool:
fn get_connection_pool(
) -> Result<r2d2::Pool<r2d2_postgres::PostgresConnectionManager<postgres::tls::NoTls>>, Error> {
let manager = PostgresConnectionManager::new(
"host=localhost user=someuser password=hunter2 dbname=mydb"
.parse()
.unwrap(),
NoTls,
);
let pool = r2d2::Pool::new(manager).unwrap();
Ok(pool)
}
And then cloned the connection pool into a warp web request
if let Ok(pool) = pool_conns {
let hello = warp::path!("get_quote" / "co_num" / String / "ctrl_num" / String)
.map(move |co, ctrl| autorate::get_quote(co, ctrl, pool.clone()));
warp::serve(hello).run(([127, 0, 0, 1], 8889)).await;
}
Then called pool.get() inside the request
let mut client = pool.get().unwrap();
but received the runtime error
thread 'main' panicked at 'Cannot start a runtime from within a runtime. This happens because a function
(like 'block_on') attempted to block the current thread while the thread is being used to drive asynchronous tasks.
My question is: in Rust, how should these two concepts work together? Specifically I mean a postgres connection pool and an async web server. I'm thinking I should have a connection pool and be able to pass it into each request to dole out connections as needed. Am I using the wrong connection pool, or just passing it in the wrong way?
Several kind folks on reddit steered me in the right direction. Instead of r2d2, I needed an async connection pool so I switched to deadpool_postgres. Ended up looking like this:
#[tokio::main]
async fn main() {
let mut cfg = Config::new();
cfg.host("yourhost");
cfg.user("youruser");
cfg.password("yourpass");
cfg.dbname("yourdb");
let mgr = Manager::new(cfg, tokio_postgres::NoTls);
let pool = Pool::new(mgr, 16);
let get_quote = warp::path!("get_quote" / "co_num" / String / "ctrl_num" / String)
.and(warp::any().map(move || pool.clone()))
.and_then(autorate::get_quote);
warp::serve(get_quote).run(([127, 0, 0, 1], 8889)).await;
}
And then to use a connection:
pub async fn get_quote(
co: String,
ctrl: String,
pool: deadpool_postgres::Pool,
) -> Result<impl warp::Reply, std::convert::Infallible> {
let co_result = Decimal::from_str(&co);
let ctrl_result = Decimal::from_str(&ctrl);
let client = pool.get().await.unwrap();
if let (Ok(co_num), Ok(ctrl_num)) = (co_result, ctrl_result) {
let orders_result = get_orders(&client, &co_num, &ctrl_num).await;
if let Ok(orders) = orders_result {
if let Ok(rated_orders) = rate_orders(orders, &client).await {
return Ok(warp::reply::json(&rated_orders));
}
}
}
Ok(warp::reply::json(&"No results".to_string()))
}
async fn get_orders(
client: &deadpool_postgres::Client,
co: &Decimal,
ctrl: &Decimal,
) -> Result<Vec<Order>, Error> {
for row in client
.query().await
...