Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Example usage of hyper with bb8 and postgres

I want to use hyper with bb8 and tokio-postgres. In every request I want to acquire a new connection from the pool. Can anybody provide me some example for this scenario? Currently I do it like this:

fn main() {
    let addr = "127.0.0.1:3000".parse().unwrap();

    let pg_mgr =
        PostgresConnectionManager::new("postgresql://auth:auth@localhost:5433/auth", NoTls);

    rt::run(future::lazy(move || {
        Pool::builder()
            .build(pg_mgr)
            .map_err(|e| eprintln!("Database error: {}", e))
            .and_then(move |pool| {
                let service = || service_fn(|req| router(req, pool.clone()));

                let server = Server::bind(&addr)
                    .serve(service)
                    .map_err(|e| eprintln!("Server error: {}", e));

                println!("Listening on http://{}", addr);
                server
            })
    }))
}

fn router(
    _req: Request<Body>,
    _pool: Pool<PostgresConnectionManager<NoTls>>,
) -> Result<Response<Body>, hyper::Error> {
    // do some staff with pool
}

But it won't compile:

error[E0597]: `pool` does not live long enough
  --> src/main.rs:22:63
   |
22 |                 let service = || service_fn(|req| router(req, pool.clone()));
   |                               -- -----------------------------^^^^----------
   |                               |  |                            |
   |                               |  |                            borrowed value does not live long enough
   |                               |  returning this value requires that `pool` is borrowed for `'static`
   |                               value captured here
...
30 |             })
   |             - `pool` dropped here while still borrowed

What am I doing wrong? How to make my case work correctly?

like image 742
sivakov512 Avatar asked Jul 24 '26 12:07

sivakov512


1 Answers

The solution is pretty simple but to understand the problem I want to provide some additional info...

  1. When you call and_then on a future to get the result, it passes the value of the variable to the closure passed to and_then which gives you ownership of that data.

  2. The method serve on hypers builder (returned by Server::bind), expects for the closure to have a static lifetime.

Now to address the problem:

  • Good: pass the value of the closure into serve, this moves it, transferring the ownership.
  • Good: service_fn is defined outside of the and_then closure so that function lives long enough
  • Bad: The closure uses the local variable pool to pass it to the service_fn.

To resolve the problem, just move the local data into your closure like so:

let service = move || service_fn(|req| router(req, pool));

like image 187
kyle Avatar answered Jul 28 '26 07:07

kyle



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!