Actix: Await for send in handle

Hello guys, I am trying to learn actix, and I want to await for a message sent to another actor inside the handle function of another message. However, I got this error. Do you know how to fix this?

Thank you!

Probably you should wrap async block with Box::pin.

There is another issue with your code. You pass self to a future that will be executed at some point. Rust won't allow for this. The future is passed to an executor and may be executed when self doesn't exist any more. send_option() can be converted to pure function or static method. This way you get rid of async block's dependency to self.

The Box::pin and self stuff doesn't seem central to this issue. The issue is that you are not in async context. Boxing is not going to save you.

You're intended to run async code in some other way afaik, but I don't know how.

Async context is not needed in case of actor handler in Actix. The handler can return a future that will be spawned in internal executor. Here is an example of how to return a future from handler when we do not need to modify actor's internal state after a future finishes:

use actix::prelude::*;

#[derive(Message)]
#[rtype(result = "Result<(), ()>")]
struct Msg;

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;
}

impl Handler<Msg> for MyActor {
    type Result = ResponseFuture<Result<(), ()>>;

    fn handle(&mut self, _: Msg, _: &mut Context<Self>) -> Self::Result {
        Box::pin(async move {
            // Some async computation
            Ok(())
        })
    }
}

If you want to modify actor's state after a future is executed, you can see an example in actix codebase.

It is worth to point out that ResponseFuture and ResponseActFuture became more permissive when it comes to future's return type since 0.10.0-alpha, which did not become stable yet.

Hi @adaqus, I tried your suggestion, but I got this new error.

My handler:

impl Handler<PlayerOption> for Player {
    type Result = ResponseFuture<bool>;

    fn handle(&mut self, msg: PlayerOption, _: &mut Context<Self>) -> Self::Result {
        let (valid, option) = self.convert_option(msg);
        let addr = self.game_addr.clone();

        Box::pin(async move {
            if valid {
                addr.send(option).await.unwrap()
            } else {
                false
            }
        })
    }
}

MessageResponse is implemented only for ResponseFuture<Result<I, E>> while your Result type is ResponseFuture<I> (ResponseFuture<bool>, to be precise). In order to make compiler accept your result type, you have to upgrade actix in your Cargo.toml to 0.10.0-alpha.3.

1 Like

It's compiled. Thank you very much. I will continue to see whether it works

1 Like