5 releases
0.2.2 | Jan 12, 2020 |
---|---|
0.2.1 | Dec 24, 2019 |
0.2.0 |
|
0.1.1 | Dec 16, 2019 |
0.1.0 | Dec 15, 2019 |
#1800 in Asynchronous
29KB
797 lines
Coerce-rs
Coerce-rs is an asynchronous (async/await) Actor runtime for Rust. It allows for extremely simple yet powerful actor-based multithreaded application development.
async/await Actors
An actor is just another word for a unit of computation. It can have mutable state, it can receive messages and perform actions.
One caveat though.. It can only do one thing at a time. This can be useful because it can alleviate the need for thread synchronisation,
usually achieved by locking (using Mutex
, RwLock
etc).
How is this achieved in Coerce?
Coerce uses Tokio's MPSC channels (tokio::sync::mpsc::channel), every actor created spawns a task listening to messages from a
Receiver
, handling and awaiting the result of the message. Every reference (ActorRef<A: Actor>
) holds a Sender<M> where A: Handler<M>
, which can be cloned.
Actors can be stopped and actor references can be retrieved by ID (currently Uuid
) from anywhere in your application. Anonymous actors are automatically dropped (and Stopped
)
when all references are dropped. Tracked actors (using global fn new_actor
) must be stopped.
Example
pub struct EchoActor {}
#[async_trait]
impl Actor for EchoActor {}
pub struct EchoMessage(String);
impl Message for EchoMessage {
type Result = String;
}
#[async_trait]
impl Handler<EchoMessage> for EchoActor {
async fn handle(
&mut self,
message: EchoMessage,
_ctx: &mut ActorHandlerContext,
) -> String {
message.0.clone()
}
}
pub async fn run() {
let mut actor = new_actor(EchoActor {}).await.unwrap();
let hello_world = "hello, world".to_string();
let result = actor.send(EchoMessage(hello_world.clone())).await;
assert_eq!(result, Ok(hello_world));
}
Timer Example
pub struct EchoActor {}
#[async_trait]
impl Actor for EchoActor {}
pub struct EchoMessage(String);
impl Message for EchoMessage {
type Result = String;
}
pub struct PrintTimer(String);
impl TimerTick for PrintTimer {}
#[async_trait]
impl Handler<PrintTimer> for EchoActor {
async fn handle(&mut self, msg: PrintTimer, _ctx: &mut ActorHandlerContext) {
println!("{}", msg.0);
}
}
pub async fn run() {
let mut actor = new_actor(EchoActor {}).await.unwrap();
let hello_world = "hello world!".to_string();
// print "hello world!" every 5 seconds
let timer = Timer::start(actor.clone(), Duration::from_secs(5), TimerTick(hello_world));
// timer is stopped when handle is out of scope or can be stopped manually by calling `.stop()`
delay_for(Duration::from_secs(20)).await;
timer.stop();
}
Dependencies
~5.5MB
~94K SLoC