简体   繁体   中英

How do I use tokio_postgres with Warp?

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
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM