Another actor library! Why another? I really like the actor model for development, and wanted something simple I could use on top of tokio.
toml
[dependencies]
tiny-tokio-actor = "0.2"
Lets define an actor. First import the necessary crate:
rust
use tiny_tokio_actor::*;
Next define the message we will be sending on the actor system's message bus: ```rust // Define the system event bus message
struct TestEvent(String);
impl SystemEvent for TestEvent {} ```
Next define the actor struct. When implementing the Actor
trait, you can override
the default pre_start()
and post_stop()
methods:
```rust
struct TestActor { counter: usize }
impl Actor
async fn post_stop(&mut self, ctx: &mut ActorContext<TestEvent>) {
ctx.system.publish(TestEvent(format!("Actor '{}' stopped.", ctx.path)));
}
} ```
Next define a message you want the actor to handle. Note that you also define the
response you expect back from the actor. If you do not want a resposne back you can
simpy use ()
as response type.
```rust
struct TestMessage(String);
impl Message for TestMessage { type Response = String; } ```
Now implement the behaviour we want from the actor when we receive the message: ```rust
impl Handler
You can define more messages and behaviours you want the actor to handle. For example, lets
define an OtherMessage
we will let our actor handle:
```rust
struct OtherMessage(usize);
impl Message for OtherMessage { type Response = usize; }
// What the actor should do with the other message
impl Handler
We can now test out our actor and send the two message types to it: ```rust
async fn multimessage() { if std::env::var("RUSTLOG").iserr() { std::env::setvar("RUSTLOG", "trace"); } let _ = envlogger::builder().istest(true).tryinit();
let actor = TestActor { counter: 0 };
let bus = EventBus::<TestEvent>::new(1000);
let system = ActorSystem::new("test", bus);
let mut actor_ref = system.create_actor("test-actor", actor).await.unwrap();
let mut events = system.events();
tokio::spawn(async move {
loop {
match events.recv().await {
Ok(event) => println!("Received event! {:?}", event),
Err(err) => println!("Error receivng event!!! {:?}", err)
}
}
});
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
let msg_a = TestMessage("hello world!".to_string());
let response_a = actor_ref.ask(msg_a).await.unwrap();
assert_eq!(response_a, "Ping!".to_string());
let msg_b = OtherMessage(10);
let response_b = actor_ref.ask(msg_b).await.unwrap();
assert_eq!(response_b, 11);
} ```
So basically this library provides: * An actor system with a message bus * A strongly typed actor with one or more message handlers * Actors referenced through ActorPaths and ActorRefs
See the docs, examples, and integration tests for more detailed examples.
Library is still incubating! There is still a lot to be done and the API is still unstable! The todo list so far: * Supervisor hierarchy * Create macros to make the defining of actors a lot simpler
Projects / blog posts that are worth checking out: * Coerce-rs * Actors with Tokio * Unbounded channel deadlock risk