1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
//! # Acteur Actor System
//!
//! An safe & opinionated actor-like framework written in Rust that just works. Simple, robust, fast, documented.
//!
//!<div align="center">
//!   <!-- Crates version -->
//!   <a href="https://crates.io/crates/acteur">
//!     <img src="https://img.shields.io/crates/v/acteur.svg?style=flat-square"
//!     alt="Crates.io version" />
//!   </a>
//!   <!-- docs.rs docs -->
//!   <a href="https://docs.rs/acteur">
//!     <img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
//!       alt="docs.rs docs" />
//!   </a>
//! </div>
//!
//! ## Status update
//!
//! #### Update 1:
//! So, I took some time to think about this framework and have intention to move it into business
//! logic + distributed framework. The idea is to make a framework that allows you to write identified
//! aggregates/models/actors without much burden.
//!
//! #### Update 2:
//! I'm playing with raft and sled in order to implement the cluster part. You can it in the file
//! playing_with_raft.rs
//!
//! ## Motivation
//!
//! Actors are cool. Many people write about them and Actix rules the benchmarks. But to write a backend system
//! spawning several servers using actors is not easy. Actually, it bring many other complexities. But actors are
//! not a bad abstraction, but they are a solution for concurrency, not for business logic organization. They
//! tangentially solve some problems and that is nice, but introduce others. So, this framework seeks to implement
//! a framework which implement something very similar to Actors but with many adaptations and niceties in order
//! to write business logic.
//!
//! Said that, Acteur is provably **not** the tool you want if:
//!
//!  - You want to have a full ACID compliant system
//!  - You want to fully follow the Actor model
//!  - You need to scale to A LOT of traffic. In which case you will need more than one server. (I'm planning to
//!  implement some multi-server clustering, but for now, only one server).
//!
//! But it may help you if you want:
//!
//!  - To have a database but not incur in the cost of READ, APPLY, SAVE, and instead you want to keep object
//!  instances in RAM.
//!  - You don't want to deal with optimistic concurrency and you want the messages to process one by one for each
//!  ID, but concurrently between IDs.
//!  - You want to make an backend for an online videogame with many entities interacting at the same time but don't
//!  want to go all the way with ECS.
//!
//! ## Main features of Acteur
//!
//! This actor system is a bit different than other frameworks. It work under the following premises:
//!  - **High-level**: The framework is oriented to map business logic rather than task concurrency.
//!  - **Simple**: The API should be small, simple and intuitive. No surprises.
//!  - **Concurrent**: The system should be fast and use all available CPU cores.
//!  - **Documented**: Everything must be documented with exhaustive examples.
//!
//! ### Regarding the implementation:
//!
//!  - Acteur is **asynchronous** and uses `async_std` under the hood.
//!  - Actors have an *ID* which its type is defined by the developer.
//!  - Messages are routed to an *Actor* and an *ID* .
//!  - Actor life-cycle is *automatically* managed by the framework.
//!  - Messages for the same Actor & ID are *sequential*. Everything else is executed **concurrently**.
//!  - Services are provided for other concurrency forms.
//!  - Services **don't** have ID and are concurrent.
//!  - Services can **subscribe** to messages and everyone can **publish** messages.
//!  - Acteur is **global**, only one instance can exist.
//!
//! ### State of the implementation
//!
//! My main focus of work now is in adding concurrency and improving ergonomics. Features already implemented:
//!
//! - ☑️ Actor / Service is activated on first message
//! - ☑️ Actor can send messages to other actors / services
//! - ☑️ System can send messages to any actor / service
//! - ☑️ Actors / Services can optionally, respond to messages
//! - ☑️ Services: statefull or stateless, without ID (like real actors) and concurrent.
//! - ☑️ Automatic deallocation of unused actors (after 5 minutes without messages)
//! - ☑️ Services can subscribe to messages
//! - □ Actor deallocation configuration (based in RAM, Actor count or timeout)
//! - □ Clustering: Implement Raft in order to assign each actor to a different server
//!
//! ## Acteur structure
//!
//! In order to use Acteur you just need to implement the correct trait and Acteur will
//! automatically use your implementation when a message is routed to your Actor/Service.
//!
//! The main traits are:
//!
//! - [Actor](./trait.Actor.html): Represents an actor
//! - [Service](./trait.Service.html): Represents a service
//!
//! Just implement them and your Actor/Service is ready to use.
//!
//! For Actors you have two traits in order to handle messages:
//!
//! - [Receive](./trait.Receive.html): Receives a message without responding to it. The most
//! efficient way to handle messages.
//! - [Respond](./trait.Respond.html): Receives a message and allows to respond to it. Forces
//! to sender to await until the actor respond.
//!
//! For Services you have other two traits.
//!
//! - [Listen](./trait.Listen.html): Receives a message without responding to it. The most efficient way
//! to handle messages.
//! - [Serve](./trait.Serve.html): Receives a message and allows to respond to it. Forces to sender to
//! await until the actor respond.
//!
//! ### Why are you using 4 different trait instead of 1 or 2?
//!
//! I tried to merge Traits but I didn't find how to do it because:
//!
//! A) The handle method contains the ActorAssistant and ServiceAssistant types in the signatures,
//! witch have different types.
//! B) I don't like to create a response channel for EVERY message when many messages don't need a response.
//!
//! Both blocks make 4 combinations. Receive/Respond for Actors and Listen/Serve for Services.
//!
//! I'm still trying to improve the naming and ergonomics. I think the concept will remain, but the ergonomics may change a bit.
//!
//! ## Actors vs Services
//!
//! Acteur provides 2 ways of concurrency. Actors and Services.
//!
//! ### Actors
//!
//! Actors have an ID and will consume messages directed to the same Actor's ID sequentially.
//! That means that if you send 2 messages to the Actor User-32, they will be handled sequentially.
//! On the other side, if you send a message to the Actor User-32 and other to the User-52 the
//! messages will be handled concurrently.
//!
//! That means, Actors instances keep messages order for the same ID, but not between different IDs.
//!
//! ### Services
//!
//! Services, on the other side, have no ID and they are concurrent. That means that you choose
//! how many instances of the Service there will be (Acteur provides a default). Services can
//! or can't have an State, but if they have, they require to be Sync (aka Mutex<state>).
//!
//! In short. Services are more like normal Actors (or, you can think as normal web services)
//! but with some preset concurrency factor. You can have many instances and there is
//! no synchronization of any type when consuming messages. Think of them as the primitive you
//! use when you want to create something that doesn't fit the Actors model in this framework.
//!
//! ### Use cases
//!
//! Choose Actor for Entities (Users, Invoices, Players, anything which their instances are identified).
//!
//! Choose Services for Business Logic, Infrastructure, Adapters, etc (Storage, DB access, HTTP services,
//! calculations of some sort that doesn't belong to any Actor, etc) and for subscribing to messages (Pub/Sub)
//!
//! ## Subscription or Pub/Sub
//!
//! Sometime we don't want to know who should receive the message but to subscribe to a type and wait.
//! Acteur models the Pub/Sub patter with Services. Actors in Acteur can't perform subscriptions as
//! that would require the framework to know all possible IDs of all possible Actor instances in
//! order to direct the message to the correct one (or all) and it doesn't play well with the deallocation
//! of unused actors.
//!
//! If you want to send messages to some Actors from a Subscription, you can create a Service that
//! subscribes to a message and then figures out to what Actor IDs to send the message. For example,
//! doing a query in the DB/Service in order to get the set of IDs that need to receive some message.
//!
//! Unlike sending/calling to services/actors, publishing doesn't know who needs to receive the
//! message in compilation time. That is the reason behind requiring the Services to subscribe in
//! runtime to any message they want to receive. In order to ensure that services perform the
//! subscriptions, it is a good idea to run `acteur.preload_service<Service>();` for each service
//! that should perform any subscription at the beginning of your Application start.
//!
//! ## Simple Example
//!
//! ```rust,no_run
//! use acteur::{Actor, Receive, ActorAssistant, Acteur};
//! use async_trait::async_trait;
//!
//! #[derive(Debug)]
//! struct Employee {
//!     salary: u32
//! }
//!
//! #[async_trait]
//! impl Actor for Employee {
//!     type Id = u32;
//!
//!     async fn activate(_: Self::Id, _: &ActorAssistant<Self>) -> Self {
//!         Employee {
//!             salary: 0 // Load from DB or set a default,
//!         }
//!     }
//! }
//!
//! #[derive(Debug)]
//! struct SalaryChanged(u32);
//!
//! #[async_trait]
//! impl Receive<SalaryChanged> for Employee {
//!     async fn handle(&mut self, message: SalaryChanged, _: &ActorAssistant<Employee>) {
//!         self.salary = message.0;
//!     }
//! }
//!
//! fn main() {
//!     let sys = Acteur::new();
//!
//!     sys.send_to_actor_sync::<Employee, SalaryChanged>(42, SalaryChanged(55000));
//!
//!     sys.wait_until_stopped();
//! }
//!
//! ```
//!
//! ## Why another Actors framework?
//!
//! Somethings bothered me.
//!
//! 1. Actor systems are a concurrency level but I see example of them being used for business logic. Using
//! a normal HTTP framework + SQL feels more natural than using Actix.
//! 2. In order to use Actix you need to learn how it works. You need to manage the concurrency,
//! the addresses, etc
//! 3. Unsafe. I don't want unsafe. I wouldn't trust myself to do something like this in C++,
//! therefore, I don't want to have unsafe code. Rust opens the door to do these kind of projects
//! to people with less than 10 years of experience in C/C++ in a safer way.
//!
//! After async_std 1.0 announcement and speaking with some friends I started to envision how I would
//! like an actor framework be. Not that Actix and others are wrong, but they are too low level in my
//! opinion and not for business logic. I wanted something that just runs without leaking so many underlying
//! concepts. At the same time I don't think that competing for the last nanosecond is healthy. Even less
//! if the framework is already super fast.
//!
//! ## Common patterns
//!
//! This section will be updated with common patters you can use in your applications. If
//! you have one you want to add or just a question of how to so something, let me know with a GitHub Issue.
//!
//! ### Web server
//!
//! Given that all actors are managed by the framework, it is really easy to have, for
//! example, Rocket or Tide getting new HTTP calls and just calling `acteur.call_service` or
//! `acteur.call_actor` and wait for the response. You can use the sync version of the call
//! if you are working with synchronous code. Keep in mind that you can clone Acteur and send
//! it to as many threads/struct you need.
//!
//! ```rust,no_run
//!
//! use acteur::Acteur;
//!
//! let acteur = Acteur::new();
//!
//! // You can clone and send it to another thread/struct
//! let acteur2 = acteur.clone();
//!
//! ```
//!
//! If you need actors to query databases it would, generally, be a good idea to keep the database
//! connection / pool in a service, where you can handle connection errors, reconnect in case of error
//! and where you can control the concurrency.
//!
//! ## Error handling
//!
//! If you have operation that can error it is better if you encode them in services and reserve
//! Actors to operations that cannot fail. For example, database connections, network connections, etc.
//!
//! It is perfectly ok to encode a failure, from the point of view of the business rules, in an actor, for
//! example, in a videogame, where a character cannot attack another character because the second is
//! invulnerable.
//!
//! So, keep anything that can fail because external circumstances (network, hard drive, etc) in services
//! and let actors to request the services for whatever they need.
//!
//! If you have an error that should stop the application startup like database connections, add them to
//! a service construction and use the method `preload_service` for trying to start the service on the
//! app startup and let the app crash is something goes wrong.
//!
//! ## Safe Rust
//!
//! No unsafe code was directly used in this crate. You can check in lib.rs the `#![deny(unsafe_code)]` line.
//!
//! ## Contributing
//!
//! First of all, I would be really happy if you decide to check the framework and contribute to it! Just open
//! an issue / pull request and we can check what you would like to implement. Check more about contributing in
//! here: [https://github.com/DavidBM/acteur-rs/blob/master/CONTRIBUTING.md]()
//!
//! ## License
//!
//! <sup>
//! Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
//! 2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
//! </sup>
//!
//! <br/>
//!
//! <sub>
//! Unless you explicitly state otherwise, any contribution intentionally submitted
//! for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
//! be dual licensed as above, without any additional terms or conditions.
//! </sub>
//!

#![deny(unsafe_code)]

#[macro_use]
mod utils;
mod actors;
mod facade;
mod services;
mod system_director;

pub use facade::Acteur;

pub use actors::actor::Actor;
pub use actors::assistant::ActorAssistant;
pub use actors::handle::{Receive, Respond};

pub use services::handle::{Listen, Serve};
pub use services::service::{Service, ServiceConcurrency, ServiceConfiguration};
pub use services::system_facade::ServiceAssistant;