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:

  1. pub trait Model : Sized {
  2. /// The message type used throughout the system.
  3. /// `Actor.receive` expects this type
  4. type Msg: Message;
  5.  
  6. /// Dispatcher executes actors and futures
  7. type Dis: Dispatcher;
  8.  
  9. /// Logger provides global logging, e.g. info!("hello");
  10. type Log: LoggerProps<Msg = Self::Msg>;
  11.  
  12. /// Dead letters subscribes to the dead letters channel
  13. type Ded: DeadLetterProps<Msg = Self::Msg>;
  14.  
  15. /// Timer provides message scheduling, e.g. `ctx.schedule_once`
  16. type Tmr: TimerFactory<Msg = Self::Msg>;
  17.  
  18. /// Event store provides the storage system for events/messages
  19. type Evs: EventStore<Msg=Self::Msg>;
  20.  
  21. type Tcp: IoManagerProps<Msg = Self::Msg>;
  22. type Udp: IoManagerProps<Msg = Self::Msg>;
  23. }

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:

  1. extern crate riker;
  2. extern crate riker_default;
  3.  
  4. use riker::actors::*;
  5. use riker_default::DefaultModel;
  6.  
  7. // Get a default model with String as the message type
  8. let model: DefaultModel<String> = DefaultModel::new();
  9. 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:

  1. extern crate riker;
  2. extern crate riker_default;
  3.  
  4. use riker::actors::*;
  5. use riker_default::*; // <-- we're still going to use some default modules
  6.  
  7. struct MyModel;
  8.  
  9. impl Model for MyModel {
  10. type Msg = String;
  11. type Dis = ThreadPoolDispatcher;
  12. type Ded = DeadLettersActor<Self::Msg>;
  13. type Tmr = BasicTimer<Self::Msg>;
  14. type Evs = Redis<Self::Msg>; // <-- a module to provide Redis storage
  15. type Tcp = TcpManager<Self::Msg>;
  16. type Udp = TcpManager<Self::Msg>;
  17. type Log = MyLogger<Self::Msg>; // <-- our own Log module
  18. }
  19.  
  20. let sys = ActorSystem::new(&MyModel).unwrap();