tiny_tokio_actor/lib.rs
1//! A Simple Tiny Tokio Actor Crate
2//!
3//! This crate provides a minimally functioning actor system with a common
4//! event bus. Tokio unbounded channels are used for the mailbox of the
5//! actors, and actor behaviour (defined through the [`Handler`] trait) can
6//! use the request+response pattern (using tokio oneshot channel for
7//! responses). You an send messages to actors either through a `tell`
8//! where the method does not provide a response, or an `ask`. The `ask`
9//! method does provide a response
10//!
11//! Example
12//! ```rust,no_run
13//! use tiny_tokio_actor::*;
14//!
15//! // The event message you may want to publish to the system event bus.
16//! #[derive(Clone, Debug)]
17//! struct TestEvent(String);
18//!
19//! // Mark the struct as a system event message.
20//! impl SystemEvent for TestEvent {}
21//!
22//! // The actor struct must be Send + Sync but need not be Clone
23//! #[derive(Default)]
24//! struct TestActor {
25//! counter: usize
26//! }
27//!
28//! // Mark the struct as an actor. Note that you can optionally override
29//! // some default methods here like `timeout()` and `supervision_stragegy()`.
30//! // See the [`Actor`] trait for details.
31//! impl Actor<TestEvent> for TestActor {}
32//!
33//! // The message the actor will expect. It must derive Clone.
34//! // Debug is not required.
35//! #[derive(Clone, Debug)]
36//! struct TestMessage(String);
37//!
38//! // Mark the message struct as an actor message. Note that we
39//! // also define the response we expect back from this message.
40//! // If no response is desired, just use `()`.
41//! impl Message for TestMessage {
42//! type Response = String;
43//! }
44//!
45//! // Define the behaviour of the actor. Note that the `handle` method
46//! // has a `String` return type because that is what we defined the
47//! // Response to be of `TestMessage`. As the method is async, we have
48//! // to annotate the implementation with the `async_trait` macro (a
49//! // re-export of the `async_trait` crate).
50//! #[async_trait]
51//! impl Handler<TestEvent, TestMessage> for TestActor {
52//! async fn handle(&mut self, msg: TestMessage, ctx: &mut ActorContext<TestEvent>) -> String {
53//! self.counter += 1;
54//! ctx.system.publish(TestEvent(format!("message received by '{}'", ctx.path)));
55//! "Ping!".to_string()
56//! }
57//! }
58//!
59//! #[tokio::main]
60//! pub async fn main() -> Result<(), ActorError> {
61//!
62//! // Create the actor
63//! let actor = TestActor { counter: 0 };
64//! // Create the message we will send
65//! let msg = TestMessage("hello world!".to_string());
66//!
67//! // Create the system event bus
68//! let bus = EventBus::<TestEvent>::new(1000);
69//! // Create the actor system with the event bus
70//! let system = ActorSystem::new("test", bus);
71//! // Launch the actor on the actor system
72//! let actor_ref = system.create_actor("test-actor", actor).await?;
73//!
74//! // Listen for events on the system event bus
75//! let mut events: EventReceiver<TestEvent> = system.events();
76//! tokio::spawn(async move {
77//! loop {
78//! match events.recv().await {
79//! Ok(event) => println!("Received event! {:?}", event),
80//! Err(err) => println!("Error receivng event!!! {:?}", err)
81//! }
82//! }
83//! });
84//!
85//! // Wait a little for the actor to start up
86//! tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
87//!
88//! // Send the actor the message through an `ask` from which we will
89//! // get a response
90//! let response = actor_ref.ask(msg).await?;
91//! println!("Response: {}", response);
92//! Ok(())
93//! }
94//! ```
95
96mod actor;
97mod bus;
98mod system;
99
100pub use actor::{
101 supervision::{RetryStrategy, SupervisionStrategy},
102 Actor, ActorContext, ActorError, ActorPath, ActorRef, Handler, Message,
103};
104pub mod supervision {
105 //! Actor Supervision Strategies
106 //!
107 //! To supervise actor startup, you can choose to just have the actor Stop,
108 //! or set a [`super::RetryStrategy`]. There are three built-in strategies you can
109 //! use: [`NoIntervalStrategy`], [`FixedIntervalStrategy`],
110 //! and [`ExponentialBackoffStrategy`].
111 //!
112 //! You can also opt to create your own strategy by implementing the provided
113 //! [`super::RetryStrategy`] trait.
114 pub use crate::actor::supervision::{
115 ExponentialBackoffStrategy, FixedIntervalStrategy, NoIntervalStrategy,
116 };
117}
118pub use bus::{EventBus, EventReceiver};
119pub use system::{ActorSystem, SystemEvent};
120
121pub use async_trait::async_trait;
122pub use tokio::time::Duration;