spaad
spaad copied to clipboard
Support For Custom Context With Multiple Actor Instances
Hey there, I just discovered this along with xtra and while trying to decide whether or not to use spaad I needed to find a way to spawn actors with the message-stealing strategy, but I couldn't find a way to do it with the current version of spaad. It would be great if we could find a way to do that with spaad.
Good job on both libraries, by-the-way. I like the minimal, but still rather functional design, and using spaad creates a rather interesting scenario with the actors almost abstracted out of sight. I'm still deciding whether I like invisible actors or not, but I think I've got to try using it a little bit to make up my mind. :)
Hi, do you mean having multiple actors on one address, just to check?
Yeah. Essentially a way to do what you have in the example here:
let (addr, mut ctx) = Context::new(Some(32));
for n in 0..3 {
smol::spawn(ctx.attach(MyActor::new(n))).detach();
}
ctx.run(MyActor::new(4)).await;
So that multiple actor instances can handle messages sent to the one addr.
After thinking about it, though, I think I might prefer to to just use xtra directly, so don't bother working on this feature just for me. :slightly_smiling_face:
I'm going to be doing some experimentation with it and I might end up trying to implement it if I find it useful, but I'll have to do some more testing first.
Anyway, this is what I settled on using for now, which is almost straight up xtra with just a small macro for implementing the handlers. I figured I'd share here, just in case the perspective helps to share a user's ( my ) use-case and preference ( so far ):
/// Macro to easily add handlers handlers for [`xtra`] actors.
///
/// ## Usage Example
///
/// ```
/// pub struct Listener;
/// impl Actor for Listener {}
///
/// pub struct Hello;
/// impl Message for Hello {
/// type Result =
/// }
///
/// pub struct Goodbye;
/// impl Message for Goodbye {
/// type Result = ();
/// }
///
/// crate::actor_handlers!(Listener, {
/// async fn handle_hello(&mut self, _: Hello, _ctx: &mut Context<Self>) {
/// println!("Hello! 👋")
/// }
///
/// async fn handle_stop(&mut self, _: Goodbye, _ctx: &mut Context<Self>) {
/// println!("Goodbye. 😔");
/// }
/// });
/// ```
#[macro_export(crate)]
macro_rules! actor_handlers {
(
$actor:ty,
{
$(
$(#[$attrs:meta])*
async fn $handler:ident(&mut self, $msg:tt: $message_type:path, $ctx:ident: &mut Context<Self>) $(-> $result:path )? {
$($bodyTokens:tt)*
}
)*
}
$(,)?
) => {
impl $actor {
$(
async fn $handler(&mut self, $msg: $message_type, $ctx: &mut xtra::Context<Self>) $(-> $result )? {
$($bodyTokens)*
}
)*
}
$(
#[async_trait::async_trait]
impl xtra::Handler<$message_type> for $actor {
async fn handle(&mut self, msg: $message_type, ctx: &mut xtra::Context<Self>) $(-> $result )? {
self.$handler(msg, ctx).await
}
}
)*
};
}
The biggest motivation for me to not just use xtra plain is the problem with IDE completion when using using the #[async_trait] macro. When you put many ( but maybe not all ) attribute macros on an impl block, while I'm typing and I hit the period, the IDE will, instead of providing auto-complete options, just report a syntax error from the macro, because the macro just aborts processing because of my invalid syntax. it essentially kills all of Rust analyzer's auto-complete while implementing the function body.
Using spaad solved that issue for me, probably due to the way you implemented the macro. I should probably just open an issue on either Rust analyzer or async_trait, but I hadn't wanted to spend the time to investigate the issue yet, so I just used the workaround above, and I think I don't dislike it horribly yet. :)
Anyway, that's all a little off-topic, but it's not really an actionable item so I didn't know if it warranted another issue.
Hmm, that Rust analyzer issue is really strange! I'm using IntelliJ Rust so this hasn't been an issue.
The main issue with exposing this functionality would be finding a nice way to do it on the spaad side! I'm not exactly sure what kind of interface would be best here. However, if you've got a different solution, then maybe it's not very important. Could be nice to have later though.
Hmm, that Rust analyzer issue is really strange! I'm using IntelliJ Rust so this hasn't been an issue.
I just tested updating rust-analyzer to the latest version and it looks like it's fixed! Yay! :tada: That helps my situation a lot.