Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not possible to use ask-pattern from inside recv function of an actor #164

Open
Superhepper opened this issue May 8, 2021 · 4 comments
Open

Comments

@Superhepper
Copy link

I wonder if it is possible to use the ask pattern from inside recv function in actor to make a blocking call to another actor in the same system. Because when I try to do that I always get an error regarding LocalPool.

I have made a very simple example (see code below) where I try to use the ask-pattern from inside another actors recv function. But this only results in the following error:

thread 'pool-thread-#3' panicked at 'cannot execute `LocalPool` executor from within another executor: EnterError', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.14/src/local_pool.rs:78:26

main.rs

mod ask;
mod reply;

use ask::{AskActor, AskActorMsg, PrintNewSentenceRequest};
use reply::ReplyActor;

use riker::actors::*;

fn main() {
    let sys = ActorSystem::new().unwrap();

    let reply_actor = sys
        .actor_of_args::<ReplyActor, _>("ReplyActor", "new".to_string())
        .unwrap();
    let ask_actor = sys
        .actor_of_args::<AskActor, _>("AskActor", reply_actor)
        .unwrap();

    ask_actor.tell(
        AskActorMsg::PrintNewSentenceRequest(PrintNewSentenceRequest {}),
        None,
    );

    std::thread::sleep(std::time::Duration::from_millis(500));
}

ask.rs

use crate::reply::{PrefixRequest, PrefixResponse, ReplyActorMsg};
use futures::executor::block_on;
use futures::future::RemoteHandle;
use riker::actors::*;
use riker_patterns::ask::*;

#[derive(Debug, Clone)]
pub struct PrintNewSentenceRequest {}

#[actor(PrintNewSentenceRequest)]
#[derive(Debug, Clone)]
pub struct AskActor {
    reply_actor: ActorRef<ReplyActorMsg>,
}

impl ActorFactoryArgs<ActorRef<ReplyActorMsg>> for AskActor {
    fn create_args(reply_actor: ActorRef<ReplyActorMsg>) -> Self {
        AskActor { reply_actor }
    }
}

impl Actor for AskActor {
    type Msg = AskActorMsg;

    fn recv(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, sender: Sender) {
        self.receive(ctx, msg, sender)
    }
}

impl Receive<PrintNewSentenceRequest> for AskActor {
    type Msg = AskActorMsg;

    fn receive(&mut self, ctx: &Context<Self::Msg>, _: PrintNewSentenceRequest, _: Sender) {
        let r: RemoteHandle<PrefixResponse> = ask(
            &ctx.system,
            &self.reply_actor,
            ReplyActorMsg::PrefixRequest(PrefixRequest {
                word: "ball".to_string(),
            }),
        );

        let response = block_on(r);

        println!("Received new sentence: {}", response.sentence);
    }
}

reply.rs

use riker::actors::*;

#[derive(Debug, Clone)]
pub struct PrefixRequest {
    pub word: String,
}

#[derive(Debug, Clone)]
pub struct PrefixResponse {
    pub sentence: String,
}

#[actor(PrefixRequest)]
#[derive(Debug, Clone)]
pub struct ReplyActor {
    prefix: String,
}

impl ActorFactoryArgs<String> for ReplyActor {
    fn create_args(prefix: String) -> Self {
        ReplyActor { prefix }
    }
}

impl Actor for ReplyActor {
    type Msg = ReplyActorMsg;

    fn recv(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, sender: Sender) {
        self.receive(ctx, msg, sender)
    }
}

impl Receive<PrefixRequest> for ReplyActor {
    type Msg = ReplyActorMsg;

    fn receive(&mut self, _: &Context<Self::Msg>, request: PrefixRequest, sender: Sender) {
        sender
            .as_ref()
            .clone()
            .unwrap()
            .try_tell(
                PrefixResponse {
                    sentence: format!("{} {}", self.prefix, request.word),
                },
                None,
            )
            .unwrap()
    }
}
@gallegogt
Copy link

hi @Superhepper It is a limitation that the ThreadPool used internally by ricker , which belongs to the crate futures::executor

rust-lang/futures-rs#2090

@Superhepper
Copy link
Author

So it would be possible if I could bring the future to completion using another thread pool like tokio?

@gallegogt
Copy link

So it would be possible if I could bring the future to completion using another thread pool like tokio?

yes, you can use tokio or async_std::task::block_on instead of futures::executor::block_on

@Superhepper
Copy link
Author

Thanks for the answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants