spaad
spaad copied to clipboard
Not waiting for the response using await doesn't work
In the README it says:
If you do not want to await for the message to complete processing, you can do the following:
let _ = my_actor.print(); // Binding to avoid #[must_use] warning on Future
This is not actually true. If you do not await on a future it will not be executed. Since the generated handles will call xtra::Address::send the actual message will not be sent to the actor at all if the returned future is not awaited. The documentation for xtra::Address::send explicitly mentions this: "Like most futures, this must be polled to actually send the message."
You can test this by comparing the result of these:
use std::time::Duration;
#[spaad::entangled]
pub struct ScanTest {
}
#[spaad::entangled]
impl xtra::Actor for ScanTest {}
#[spaad::entangled]
impl ScanTest {
#[spaad::spawn]
pub fn new() -> Self {
ScanTest { }
}
#[spaad::handler]
pub fn print(&mut self) {
println!("called!");
}
}
#[tokio::main]
async fn main() {
let mut s = ScanTest::new(&mut xtra::spawn::Tokio::Global);
s.print();
std::thread::sleep(Duration::from_secs(5));
}
with this:
use std::time::Duration;
#[spaad::entangled]
pub struct ScanTest {
}
#[spaad::entangled]
impl xtra::Actor for ScanTest {}
#[spaad::entangled]
impl ScanTest {
#[spaad::spawn]
pub fn new() -> Self {
ScanTest { }
}
#[spaad::handler]
pub fn print(&mut self) {
println!("called!");
}
}
#[tokio::main]
async fn main() {
let mut s = ScanTest::new(&mut xtra::spawn::Tokio::Global);
s.print().await;
std::thread::sleep(Duration::from_secs(5));
}
However you can still archive the expected result (not waiting for the result) by passing the future to tokio::spawn:
async fn main() {
let mut s = ScanTest::new(&mut xtra::spawn::Tokio::Global);
tokio::spawn(s.print());
println!("spawned!");
std::thread::sleep(Duration::from_secs(5));
}
This outputs:
spawned!
called!
IMO the documentation in README is wrong and should be corrected. Also in general I think we shouldn't encourage users to not call await/poll/pass to an executor somehow a Future since ignoring a returned impl Future doesn't do what the user would expect. (i.e.: ignoring the future will just cause it to not be executed at all)
Thanks for noting this! It's likely that at some point this functioned differently as xtra has been through many rewrites and behaviour changes - more than it has version numbers, as many were internal.
It is likely that with xtra master, we could have
let _ = my_actor.print().split_receiver().await; // Binding to avoid #[must_use] warning on Future
function the same as
tokio::spawn(my_actor.print())
However this is slightly ugly as it exposes xtra internals in a way that spaad aims to avoid. I am not really sure that the concept of spaad was well executed. I liked it at first because it was cool to be able to reduce the boilerplate and treat what is essentially a system boundary like a normal function/API. In theory, spaad's concept could work over more than just xtra, and actually work over HTTPS with a REST API or any other system boundary protocol. I just did it because I thought it was cool and convenient. Now, however, I am not so sure that these details are actually something I want to hide, especially when it comes to more advanced things like split_receiver. I am not even sure that that is what you want in the first place in most cases - I think @thomaseizinger is of the opinion that it is almost never wanted due to backpressure reasons, and I am somewhat inclined to agree now after having seen some projects use it and run into issues as a result.
I think the crux of the issue is that I am not really sure what to do with spaad. I think once the latest version of xtra is released I might publish a last version of spaad in terms of feature completeness. I am not very happy with the concept so I might just keep it updated with xtra but not advance the functionality further since I don't think it's conducive to good design. If anyone else feels differently they must feel free to challenge me on this and we can see what a good path forward is :) i.e: I want to hear why people like or dislike spaad, and use that info to move forward better.
Just confirming what you said above: Yes, not awaiting the response of a message should be used very cautiously because you are breaking the back-pressure chain. It is fine to use split_receiver but you really have to think through what you are doing.