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.