Victor D
Victor D

Reputation: 15

Async middleware, get async result before calling next middleware

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?

Upvotes: 0

Views: 382

Answers (0)

Related Questions