A safe actor-like framework that just works. Simple, robust, fast, documented.


Keywords
async, system, actor, messages, actors, acteur, actor-model, concurrency
Licenses
Apache-2.0/MIT

Documentation

Acteur Actor System

A safe actor system written in Rust that just works. Simple, robust, fast, documented.

Main Features

Acteur uses async_std under the hood. This actor system work under the following premises:

  • Simplicity: The API should be small, simple and intuitive
  • Speed: The system should be fast and use all available CPU cores
  • Documented: Everything must be documented with exhaustive examples

Regarding the implementation:

  • Actors have an ID which type is defined by the user for each Actor type
  • Messages are routed to an Actor and an ID
  • Actor life-cycle is automatically handled by the framework
  • Actors are automatically de/allocated depending of their usage
  • Messages for the same Actor & ID are ordered. Everything else is executed concurrently.

State of the implementation

  • Actor is activated on first message
  • Actor can send messages to other actors
  • System can send messages to any actor
  • Actor self stop
  • Stop waits for all actors to consume all messages
  • System statistics
  • Automatic deallocation of unused actors
  • Subscribe to message
  • Fan-out messages
  • RPC like messages between actors
  • Services (statefull or stateless, like actors, without ID and processing messages concurrently)
  • Allow more than 150.000 queued messages per actor (waiting for async_std to have unbounded channels: https://github.com/async-rs/async-std/issues/212)

Examples

Simple example

use acteur::{Acteur, Actor, Assistant, Receive};
use async_trait::async_trait;

#[derive(Debug)]
struct Employee {
    salary: u32,
}

#[async_trait]
impl Actor for Employee {
    type Id = u32;

    async fn activate(_: Self::Id) -> Self {
        Employee {
            salary: 0, //Load from DB or set a default,
        }
    }
}

#[derive(Debug)]
struct SalaryChanged(u32);

#[async_trait]
impl Receive<SalaryChanged> for Employee {
    async fn handle(&mut self, message: SalaryChanged, _: &Assistant<Employee>) {
        self.salary = message.0;
    }
}

fn main() {
    let sys = Acteur::new();

    sys.send_sync::<Employee, SalaryChanged>(42, SalaryChanged(55000));

    sys.wait_until_stopped();
}

You can find more examples in the examples folder.

Safe Rust

No unsafe code was directly used in this crate. You can check in lib.rs the #![deny(unsafe_code)] line.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.