1

Using this minimal asynchronous actix-web server

use actix_web::{http, server, App, HttpRequest, HttpResponse,  Error}; // v. 0.7.19
use futures::Future; // v. 0.1.28

/// An Asynchronous response which will either "fail fast" on the outer `Result` or
/// return a future which may itself succeed or fail
/// The lifetime parameter is required to indicate that the future cannot outlive
/// the parameter  - the `req: &HttpRequest` - of the handler (`handle_request`)
type AsyncCResponse<'a> =
Result<Box<Future<Item = HttpResponse, Error = Error> + 'a>, Error>;

/// lifetimes have been elided but here the future in the `AsyncCResponse`
/// will have the same lifetime as the `req` HttpRequest
fn handle_request(req: &HttpRequest<()>) -> AsyncCResponse {
    // handle the request
    Ok(Box::new(futures::future::ok(HttpResponse::Ok().body("Hello World"))))
}

fn main() {
    // instantiation of an actix-web server
    server::new(move || {
        App::new()
            .resource("/", |r| {
                r.method(http::Method::GET).f(|r: &HttpRequest<()>| handle_request(r))
            })
    });
}

Compilation fails with


error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:23:69
   |
23 |                 r.method(http::Method::GET).f(|r: &HttpRequest<()>| handle_request(r))
   |                                                                     ^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 23:47...
  --> src/main.rs:23:47
   |
23 |                 r.method(http::Method::GET).f(|r: &HttpRequest<()>| handle_request(r))
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:23:84
   |
23 |                 r.method(http::Method::GET).f(|r: &HttpRequest<()>| handle_request(r))
   |                                                                                    ^
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the types are compatible:
           expected actix_web::handler::Responder
              found actix_web::handler::Responder

The definition of f in actix-web is

/// Set handler function. Usually call to this method is last call
/// during route configuration, so it does not return reference to self.
pub fn f<F, R>(&mut self, handler: F)
where
    F: Fn(&HttpRequest<S>) -> R + 'static,
    R: Responder + 'static,
{
    self.handler = InnerHandler::new(handler);
}

Do I understand correctly that compilation fails because

  • the definition of frequires that the handler F returns a response with a 'static lifetime
  • when the response returned by the given handler handle_request has a lifetime bound to that of the HttpRequest parameter?

Is there anything I can do to fix this without changing the definition of AsyncCResponse ?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Bruno Grieder
  • 28,128
  • 8
  • 69
  • 101
  • Does it work if you type `fn handle_request<'a>(req: &'a HttpRequest<()>) -> AsyncCResponse<'a>`? – Boiethios Jul 11 '19 at 13:31
  • @FrenchBoiethios No. Actually the (lifetime) elided version is strictly identical to what you suggested (a single ref parameter). – Bruno Grieder Jul 11 '19 at 14:06
  • I think that you cannot do what you want. The `Responder` returned by your func must be bound to a static lifetime while your `AsyncCResponse` is not. I'm not sure why there is such a restriction in Actix, tho. – Boiethios Jul 11 '19 at 14:17
  • 1
    Without changing the definition of `AsyncCResponse<'a>` , `'a` must be equal to `'static`, since `R` is restricted with `Responder + 'static`, this doesn't look possible because of `req: &HttpRequest<()>` parameter(Compiler infers a different lifetime than `'static`).You may want to try using different lifetime parameters for input and output, instead of eliding. – Ömer Erden Jul 11 '19 at 14:21
  • @ÖmerErden I could not find a suitable solution and have reengineered the whole thing. Interestingly enough, actix-web 1.0 now passes values rather than references in their handlers – Bruno Grieder Jul 12 '19 at 07:15
  • `fn handle_request(req: &HttpRequest<()>) -> AsyncCResponse<'static>` why this doesn't help to you ? ( i was pointing this on my previous comment ) – Ömer Erden Jul 12 '19 at 08:02
  • @ÖmerErden long story;;; may best explained [here](https://stackoverflow.com/questions/56975388/calling-itself-in-a-future). In short, `handle_request` generates a future where a struct reference extracted from the `HttpRequest` calls itself n the future. The resulting (future) `AsyncResponse` cannot then outlive the `HttpRequest` – Bruno Grieder Jul 12 '19 at 14:25

0 Answers0