Model & Customization
Riker requires a Model
to set the message type used throughout the system and specify modules that provide core services. Model
is a trait that can be implemented on a Rust type which is then used to create the ActorSystem
.
Model Trait
Let's take a look at the Model
trait:
- pub trait Model : Sized {
- /// The message type used throughout the system.
- /// `Actor.receive` expects this type
- type Msg: Message;
- /// Dispatcher executes actors and futures
- type Dis: Dispatcher;
- /// Logger provides global logging, e.g. info!("hello");
- type Log: LoggerProps<Msg = Self::Msg>;
- /// Dead letters subscribes to the dead letters channel
- type Ded: DeadLetterProps<Msg = Self::Msg>;
- /// Timer provides message scheduling, e.g. `ctx.schedule_once`
- type Tmr: TimerFactory<Msg = Self::Msg>;
- /// Event store provides the storage system for events/messages
- type Evs: EventStore<Msg=Self::Msg>;
- type Tcp: IoManagerProps<Msg = Self::Msg>;
- type Udp: IoManagerProps<Msg = Self::Msg>;
- }
The Model
trait consists of various trait types that are used to customize a Riker system, including the message type.
Default Model
A default model is provided by the riker-default
crate that uses default Riker modules but still allows you to specify your message type (protocol).
Using the default model:
- extern crate riker;
- extern crate riker_default;
- use riker::actors::*;
- use riker_default::DefaultModel;
- // Get a default model with String as the message type
- let model: DefaultModel<String> = DefaultModel::new();
- let sys = ActorSystem::new(&model).unwrap();
The default model helps get the initial stages of your application started. It's also a good choice for integration tests. When you're ready to use other modules, for example an event store module for a specific database, you can use your own model.
Custom Model
Since Model
is a trait it can be implemented on a simple struct.
Let's look at how we can create a model to change the event store and logging modules:
- extern crate riker;
- extern crate riker_default;
- use riker::actors::*;
- use riker_default::*; // <-- we're still going to use some default modules
- struct MyModel;
- impl Model for MyModel {
- type Msg = String;
- type Dis = ThreadPoolDispatcher;
- type Ded = DeadLettersActor<Self::Msg>;
- type Tmr = BasicTimer<Self::Msg>;
- type Evs = Redis<Self::Msg>; // <-- a module to provide Redis storage
- type Tcp = TcpManager<Self::Msg>;
- type Udp = TcpManager<Self::Msg>;
- type Log = MyLogger<Self::Msg>; // <-- our own Log module
- }
- let sys = ActorSystem::new(&MyModel).unwrap();