riker
riker copied to clipboard
Not possible to use ask-pattern from inside recv function of an actor
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()
}
}
hi @Superhepper It is a limitation that the ThreadPool used internally by ricker , which belongs to the crate futures::executor
https://github.com/rust-lang/futures-rs/issues/2090
So it would be possible if I could bring the future to completion using another thread pool like tokio?
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
Thanks for the answer.