[SOLVED] Error in Async closure: Lifetime may not live long enough; returning this value requires that `’1` must outlive `’2`

Issue

This Content is from Stack Overflow. Question asked by Davis Raymond

I’m trying to use a Mutex<Sender> inside an async closure but I’m not entirely sure why I’m getting the error below:

error: lifetime may not live long enough
   --> src/main.rs:120:41
    |
120 |       io.add_method(MARK_ITSELF, move |_| async {
    |  ________________________________--------_^
    | |                                |      |
    | |                                |      return type of closure `impl std::future::Future<Output = Result<jsonrpc::serde_json::Value, jsonrpc_http_server::jsonrpc_core::Error>>` contains a lifetime `'2`
    | |                                lifetime `'1` represents this closure's body
121 | |         trace!("Mark itself!");
122 | |         let tx = sender.lock().map_err(to_internal)?;
123 | |         tx.send(Action::MarkItself)
124 | |             .map_err(to_internal)
125 | |             .map(|_| Value::Bool(true))
126 | |     });
    | |_____^ returning this value requires that `'1` must outlive `'2`
    |
    = note: closure implements `Fn`, so references to captured variables can't escape the closure

My main function looks like this:

8 fn main() -> Result<(), failure::Error> {                                                                                                                                             
    7     env_logger::init();                                                                                                                                                               
    6     let tx = spawn_worker()?; ‣Sender<Action>                                                                                                                                         
    5     let addr: SocketAddr = env::var("ADDRESS")?.parse()?;                                                                                                                             
    4     let mut io = IoHandler::default(); ‣IoHandler                                                                                                                                     
    3     let sender = Mutex::new(tx.clone()); ‣Mutex<Sender<Action>>                                                                                                                       
>>  2     io.add_method(START_ROLL_CALL, move |_| async {                                                                                                                                   
    1         trace!("Starting roll call!");                                                                                                                                                
  114         let tx = sender.lock().map_err(to_internal)?; ‣MutexGuard<Sender<Action>>                                                                                                     
    1         tx.send(Action::StartRollCall)                                                                      
    2             .map_err(to_internal) ‣Result<(), Error>                                             
    3             .map(|_| Value::Bool(true)                                                                                                                     
    4     });                                                                                                                                                                               
    5     let sender = Mutex::new(tx.clone()); ‣Mutex<Sender<Action>>                                                                                                                       
>>  6     io.add_method(MARK_ITSELF, move |_| async {                                                                                                                                       
    7         trace!("Mark itself!");                                                                                                                                                       
    8         let tx = sender.lock().map_err(to_internal)?; ‣MutexGuard<Sender<Action>>                                                                                                     
    9         tx.send(Action::MarkItself) ‣Result<(), SendError<Action>>                                                                                                                    
   10             .map_err(to_internal) ‣Result<(), Error>                                                                                                                                  
   11             .map(|_| Value::Bool(true))                                                                                                                                               
   12     });                                                                                                                                                                               
   13     let server = ServerBuilder::new(io).start_http(&addr)?; ‣Server                                                                                                                   
   14     Ok(server.wait())                                                                                                                                                                 
   15 }                                                                                                                                                                                                                                                                                                                                                                      

The main idea is to pass the mspc sender to the closure so that the method can send the Action(An enum). Is there something I’m doing wrong? I’m a bit new to rust so I might be missing something obvious; Thanks in advance for assisting.



Solution

The problem is add_method requires that

  • your closure is static, and
  • the Future returned from your closure is static.

Try this

let sender = Arc::new(Mutex::new(tx.clone()));
io.add_method(START_ROLL_CALL, move |_| {
    let cloned_sender = sender.clone();
    async move {
        trace!("Starting roll call!");
        let tx = cloned_sender.lock().map_err(to_internal)?;
        tx.send(Action::StartRollCall)
            .map_err(to_internal)
            .map(|_| Value::Bool(true))
    }
});

Side note: you are using sync Mutex in an async environment. This undermines the benefits of async. Consider using async Mutex such as Tokio Mutex or async-lock Mutex.


This Question was asked in StackOverflow by Davis R. and Answered by wisha It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?