Expand description

Arrows

An actor framework in rust with message durability and ingestion order processing of messages. Message persistence via an embedded sqlite instance. Message content can be text or binary. Messages themselves get stored as binany in the backing store.

use crate::{Actor, Mail, Msg, Producer};
use serde::{Deserialize, Serialize};

//A sample actor
pub struct DemoActor;
impl Actor for DemoActor {
    fn receive(&mut self, incoming: Mail) -> Option<Mail> {
        match incoming {
            Mail::Trade(msg) => println!("Received: {}", msg),
            bulk @ Mail::Bulk(_) => println!("Received bulk msg: {}", bulk),
            Mail::Blank => println!("DemoActor received blank"),
        }
        Some(Msg::from_text("Message from DemoActor").into())
    }
}

//Producer implementations are called to produce actor instances.

//Produces DemoActor instances
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ActorProducer;

//Producer implementations need to be tagged with `typetag` marker.

#[typetag::serde]
impl Producer for ActorProducer {
    fn produce(&mut self) -> Box<dyn Actor> {
        Box::new(DemoActor)
    }
}

//The `define_actor` - macro actually defines a new actor `instance` in the system. The
//actor instance along with the producer - get persisted in the backing store, the actor
//instance gets activated and receives a startup signal and becomes ready to process
//incoming messages. The producer defintion gets used to restart/restore the actor as
//required.

use arrows::define_actor;

let producer = ActorProducer::default();
define_actor!("demo_actor", producer);

//At this stage - the actor instance `demo_actor` is ready for incoming messages. It
//should have already received the startup signal.

use arrows::send;

let m1 = Msg::from_text("Message to demo actor");
let m2 = Msg::from_text("Message to demo actor");
let m3 = Msg::from_text("Message to demo actor");

send!("demo_actor", (m1, m2, m3));

//Create another actor instance - demo_actor1

define_actor!("demo_actor1", ActorProducer::default());

let m4 = Msg::from_text("Message to demo actor1");
let m5 = Msg::from_text("Message to demo actor1");

let m6 = Msg::from_text("Message to demo actor");
let m7 = Msg::from_text("Message to demo actor");

//Send out multiple messages to multiple actors at one go

send!("demo_actor1", (m4, m5), "demo_actor", (m6, m7));


//Actors running in remote systems - need to be identified by the `Addr` construct:

use arrows::Addr;

let remote_actor = Addr::remote("remote_actor", "11.11.11.11:8181");

let m1 = Msg::with_text("Message to remote actor");
let m2 = Msg::with_text("Message to remote actor");

send!("remote_actor", m1, m2);

//While sending to a single actor - its not recessary to group messages within braces.

How to get started:

  1. Check the github repository out
  2. Launch an extra terminal
  3. Fire the register.sh script in the project directory.
  4. In another terminal launch the server.sh script in the same directory
  5. From previous termainal launch the send.sh script - actors should start receiving messages.

Contribution: This project is still evolving. Contributions are welcome.

Re-exports

pub use common::config::Config;
pub use demos::*;

Modules

Catalog Manages a pool of actors, exposes an API define_actor() for instantiating actors in the system. Provides internal apis for activatation/restoration of actors, a handle to backend store.

Common Common interface between implementation and client usage

Demos Contains the sample definitions. This is due to the fact that the final binary need to be cognizant of defined entitities like actor implementations and their corresponding producers.

This module defines macros for actor regsistration and invocation.

This module handles method invocation on actors. Maintains a number of Delegates equal to the number of cpus in the running nodes.

Macros

This macro defines a new actor instance in the system. It takes a literal string as actor name and an implmentation of Producer that is called to return an Actor. The actor becomes active as soon as it is defined and receives a startup signal.

Sends one or more messages to one or more actors defined in the system. This function is responsible for gathering and dispatching messages received from the macro invocation of send!. Multiple messages can be grouped for one more actors in one send! macro invocation as shown below:

Structs

Unique actor addresses based on IP, PORT and names. Some fields are later extension points

The actual payload received by actors inside a Mail enum construct

Enums

Msg content type can also be Command. Action represents tasks corresponding to Commands.

#Error Various error messages during the arrows execution path.

The Mail enum which could be Trade(single message), Bulk(multiple messages) or Blank

Traits

Actor

Producer

Functions

Compute the hash for a struct like Addr

Reconstruct a type from array of bytes such as Msg Reconstructed type must be serde json Derserialize

Convert a type into byte representation such as Addr The type needs to be serde json serializable - uses bincode underneath.

Type Definitions

Success cases mostly related to the Mail enum, error cases are this crates’ exposed erros