use async_trait::async_trait;
use std::time::Duration;
use tokio::time::{sleep, timeout};
use serviceless::{Context, EmptyStream, Handler, Message, ReplyHandle, Service};
#[derive(Default)]
struct PreferredService;
#[async_trait]
impl Service for PreferredService {
type Stream = EmptyStream<Self>;
}
struct SlowDouble(pub u32);
impl Message for SlowDouble {
type Result = u32;
}
struct Ping;
impl Message for Ping {
type Result = &'static str;
}
#[async_trait]
impl Handler<SlowDouble> for PreferredService {
async fn handle(&mut self, message: SlowDouble, _ctx: &mut Context<Self, Self::Stream>) -> u32 {
message.0 * 2
}
async fn handle_preferred(
&mut self,
message: SlowDouble,
_ctx: &mut Context<Self, Self::Stream>,
handle: ReplyHandle<SlowDouble>,
) {
tokio::spawn(async move {
sleep(Duration::from_millis(200)).await;
let _ = handle.send(message.0 * 2);
});
}
}
#[async_trait]
impl Handler<Ping> for PreferredService {
async fn handle(
&mut self,
_message: Ping,
_ctx: &mut Context<Self, Self::Stream>,
) -> &'static str {
"pong"
}
}
#[tokio::main]
async fn main() {
let (addr, run) = PreferredService.start_by_context(Context::new());
let service_handle = tokio::spawn(run);
let addr_for_slow = addr.clone();
let slow = tokio::spawn(async move { addr_for_slow.call(SlowDouble(21)).await.unwrap() });
let pong = timeout(Duration::from_millis(50), addr.call(Ping))
.await
.expect("ping should not be blocked by preferred work")
.expect("ping call should succeed");
println!("quick reply while SlowDouble is pending: {pong}");
let out = slow.await.expect("join preferred call");
println!("slow preferred reply: {out}");
addr.close_service();
service_handle.await.expect("service join failed");
}