[][src]Crate herbert

Management for actor services and message routing.

An actor is a long-lived thread that performs a specific function or set of functions and consumes a channel of requests from other threads using protocols to describe how and on what data those functions should be performed.

While the actor model has numerous benefits, exherting control over actors (such as during a shutdown event) and keeping track of all of their channels can be challenging. This module provides facilities that support the use of the actor model by addressing those challenges.

To maintain a registry of actors, keep track of their channels, and respond to control events, a special type of actor called a router is launched. A Router encapsulates the channels through which clients interact with the router and the actors it maintains. The router's registry maps an ID for each actor to an Actor type similar to Router which encapsulates the channels through which actors receive their input.

Actors are spawned through a control message to the router. They are provided an ActorContext that provides the channels over which the function receives its inputs and control messages, and a channel over which it can communicate its status back to the router.

An actor function must:

  • Use the select! macro that is re-exported from crossbeam_channel to receive from both the request channel and the control channel.
  • Convert the Any + Send trait objects it receives over the request channel into the correct concrete type.
  • Respond to ActorCtl::Stop messages it receives over the control channel by promptly stablizing its state, sending the router an ActorStatus::Stopped status message, and exiting.

Simple Example

extern crate herbert;
use herbert::prelude::*;

fn main() {
    // Create a router. This is manditory.
    let router = Router::run("example");

    // Spawn an actor, here named "herbert".
    spawn_actor!(router, "herbert", |ctx: ActorContext| {
        loop {
            select! {
                // Normal message channel.
                recv(ctx.req) -> msg => {
                    match msg {
                        Ok(any) => {
                            // Convert trait object into concrete type.
                            if let Some(value) = any.downcast_ref::<String>() {
                                // Do some work.
                                println!("received order: {}", value);
                            } else {
                                // Bad value, here we're just ignoring it.
                        Err(e) => {
                            // Error receiving a normal message, choosing to terminate.
                // Control message channel.
                recv(ctx.ctl) -> msg => {
                    match msg {
                        Ok(ActorCtl::Stop) => {
                            // We have been requested to stop.
                            // Stabilize any state and then break the loop to exit.
                        Err(e) => {
                            // Error receiving a control message, choosing to terminate.
        // Notify the router we are stopped as our last action.

    // Send our order to the "herbert" actor thread.
    send_actor!(router, "herbert", String::from("2 gorditas")).unwrap();

    // ...

    // Shut down the router.



The things you'll need.



A wrapper for sending a message to an actor.


A wrapper for executing a RouterCtl::Spawn request on a Router.



A handle to an actor.


A handle to communication channels provided to an actor function.


A handle to the actor management thread.


A request to route a message to an actor.



Messages that exhert control over actors.


Status messages sent from an actor to the supervising router.


Errors that can occur.


A control message for the router.

Type Definitions


A signature for actor thread functions.


The type signature of the messages that are consumed by actors.


A custom result type.