0

I'm trying to create a middleware with redis and actix-web.

This is what I want for my middleware:

-> Concat the request path and query_string, to create a redis key.
-> Get the value stored within redis db.
-> If not null, return this content.
-> If null, call the next service, and once it's done, store the response within redis (so it's cached for next time)

My issue is that inside my wrap_fn function I need to get the async result of redis before I try to call srv.call(req)

Let me explain:

.wrap_fn(|req, srv| {
        let fut = srv.call(req);
        async {
            let mut res = fut.await?;
            Ok(res)
        }
    })

This code work, so we get the future response within fut, then we await and respond.

Now if I want to add my logic to it:

.wrap_fn(|req, srv| {
        let path = req.path().to_string();
        let query_string = req.query_string().to_string();

        let redis_fut = async move {
            let redis_key = format!("{}:{}", path, query_string);
            redis.get(redis_key.as_str()).await
        };

        // let fut = srv.call(req);
        async {
            let redis_res: String = redis_fut.await?.unwrap();
            if redis_res.ne(format!("(nil)")) {
                 // Build and return redis content
            }
            else {
                let mut res = srv.call(req).await?; // Moved srv.call(req) here
                // Add to redis
                Ok(res)
            }
        }
    })

I must move let fut = srv.call(req); inside the async block because otherwise it will get executed even if there is a redis result. But It doesn't work because of the lifetime of srv.

error: lifetime may not live long enough
  --> src/main.rs:90:4
   |
74 |           .wrap_fn(|req, srv| {
   |                          ---- return type of closure `impl futures::Future<Output = Result<ServiceResponse, actix_web::Error>>` contains a lifetime `'2`
   |                          |
   |                          has type `&'1 actix_web::app_service::AppRouting`
...
90 | /             async {
91 | |                 let res = srv.call(req).await?;
92 | |                 Ok(res)
93 | |             }
   | |_____________^ returning this value requires that `'1` must outlive `'2`

How can I achieve this?

Victor D
  • 15
  • 6
  • 2
    [This Github issue](https://github.com/actix/actix-web/issues/2681) seems relevant. – cdhowie Mar 21 '23 at 20:39
  • 1
    Please create a minimal reproducible example. Also, post the full compiler error from `cargo check`, not your IDE. – Chayim Friedman Mar 21 '23 at 20:49
  • Thx @cdhowie. `from_fn` from `actix-web-lab` made the trick. Since the middleware is an async function I can await properly. – Victor D Mar 21 '23 at 23:14

0 Answers0