kameo 0.4.0

Fault-tolerant Async Actors Built on Tokio
Documentation

Kameo 🧚🏻

Crates.io Version Crates.io Total Downloads Crates.io License GitHub Repo stars

Fault-tolerant Async Actors Built on Tokio

  • Async: Built on tokio, actors run asyncronously in their own isolated spawned tasks.
  • Supervision: Link actors, creating dependencies through child/parent/sibbling relationships.
  • MPSC Unbounded Channels: Uses mpsc channels for messaging between actors.
  • Concurrent Queries: Support concurrent processing of queries when mutable state isn't necessary.
  • Panic Safe: Catches panics internally, allowing actors to be restarted.

Installing

Stable

[dependencies]
kameo = "*"

Nightly

Nightly allows for some cleaner apis thanks to specialization.

Notably,

  • Message::Reply and Query::Reply can be any type, not just Result types.
  • spawn_unsync and other _unsync methods are not required - !Sync actors are inferred automatically.
[dependencies]
kameo = { version = "*", features = ["nightly"] }

Defining an Actor without Macros

// Define the actor state
struct Counter {
    count: i64,
}

impl Actor for Counter {}

// Define messages
struct Inc { amount: u32 }

impl Message<Inc> for Counter {
    type Reply = Result<i64, Infallible>;

    async fn handle(&mut self, msg: Counter) -> Self::Reply {
        self.count += msg.0 as i64;
        Ok(self.count)
    }
}

Defining an Actor with Macros

// Define the actor state
#[derive(Actor)]
struct Counter {
    count: i64,
}

// Define messages
#[actor]
impl Counter {
    #[message]
    fn inc(&mut self, amount: u32) -> Result<i64, Infallible> {
        self.count += amount as i64;
        Ok(self.count)
    }
}
// Derive Actor
impl kameo::Actor for Counter {
    fn name(&self) -> Cow<'_, str> {
        Cow::Borrowed("Counter")
    }
}

// Messages
struct Inc { amount: u32 }

impl kameo::Message<Inc> for Counter {
    type Reply = Result<i64, Infallible>;

    async fn handle(&mut self, msg: &mut Inc) -> Self::Reply {
        self.inc(msg.amount)
    }
}

Spawning an Actor & Messaging

use kameo::{Spawn, ActorRef};

let counter_ref: ActorRef<Counter> = Counter { count: 0 }.spawn();

let count = counter_ref.send(Inc(42)).await?;
println!("Count is {count}");

Benchmarks

13x higher throughput when compared with Actix

benchmark

Above shows a basic benchmark for sending a message to an actor in Kameo and Actix. Always benchmark for yourself.

Sending a message to an actor

Benchmark Time
Kameo Unsync Message 432.26 ns
Kameo Sync Message 503.89 ns
Kameo Query 1.3000 µs
Actix Message 5.7545 µs

Processing fibonachi sequence in an actor up to 20

Benchmark Time
Kameo Unsync Message 18.229 µs
Kameo Sync Message 18.501 µs
Kameo Query 19.257 µs
Actix Message 27.442 µs

Contributing

Contributions are welcome! Feel free to submit pull requests, create issues, or suggest improvements.

License

kameo is dual-licensed under either:

at your option.