event_driven_library/
lib.rs

1//! [event-driven-core]: https://docs.rs/event-driven-core
2//! [event-driven-macro]: https://docs.rs/event-driven-macro
3//! [Command]: https://docs.rs/event-driven-core/latest/event_driven_core/message/trait.Command.html
4//! [Event]: https://docs.rs/event-driven-core/latest/event_driven_core/message/trait.Message.html
5//! [MessageBus]: https://docs.rs/event-driven-core/latest/event_driven_core/messagebus/index.html
6//! [Context]: https://docs.rs/event-driven-core/latest/event_driven_core/messagebus/struct.ContextManager.html
7//! [AtomicContextManager]: https://docs.rs/event-driven-core/latest/event_driven_core/messagebus/type.AtomicContextManager.html
8//!
9//! A event-driven framework for writing reliable and scalable system.
10//!
11//! At a high level, it provides a few major components:
12//!
13//! * Tools for [core components with traits][event-driven-core],
14//! * [Macros][event-driven-macro] for processing events and commands
15//!
16//!
17//! # A Tour of Event-Driven-Library
18//!
19//! Event-Driven-Library consists of a number of modules that provide a range of functionality
20//! essential for implementing messagebus-like applications in Rust. In this
21//! section, we will take a brief tour, summarizing the major APIs and
22//! their uses.
23//!
24//! ## Command & Event
25//! You can register any general struct with [Command] Derive Macro as follows:
26//! ```ignore
27//! #[derive(Command)]
28//! pub struct MakeOrder {
29//!     pub user_id: i64,
30//!     pub items: Vec<String>,
31//! }
32//! ```
33//! As you attach [Command] derive macro, MessageBus now is going to be able to understand how and where it should
34//! dispatch the command to.
35//!
36//! Likewise, you can do the same thing for Event:
37//! ```ignore
38//! #[derive(Serialize, Deserialize, Clone, Message)]
39//! #[internally_notifiable]
40//! pub struct OrderFailed {
41//!     #[identifier]
42//!     pub user_id: i64,
43//! }
44//!
45//! #[derive(Serialize, Deserialize, Clone, Message)]
46//! #[internally_notifiable]
47//! pub struct OrderSucceeded{
48//!     #[identifier]
49//!     pub user_id: i64,
50//!     pub items: Vec<String>
51//! }
52//! ```
53//! Note that use of `internally_notifiable`(or `externally_notifiable`) and `identifier` is MUST.
54//!
55//! * `internally_notifiable` is marker to let the system know that the event should be handled
56//! within the application
57//! * `externally_notifiable` is to leave `OutBox`.
58//! * `identifier` is to record aggregate id.
59//!
60//!
61//!
62//! ## Initializing Command Handlers
63//! Command handlers are responsible for handling commands in an application, the response of which is sent directly to
64//! clients. Commands are imperative in nature, meaning they specify what should be done.
65//!
66//! ```
67//! # const IGNORE_1: &str = stringify! {
68//! use event_driven_library::prelude::{init_command_handler, init_event_handler};
69//! # };
70//! # macro_rules! init_command_handler {
71//! #    ($($tt:tt)*) => {}
72//! # }
73//!
74//! init_command_handler!(
75//! {
76//!    MakeOrder: OrderHandler::make_order,
77//!    CancelOrder: OrderHandler::cancel_order
78//! }
79//! );
80//! ```
81//! In the example above, you see `MakeOrder` is mapped to `OrderHandler::make_order`, handler in application layer.
82//!
83//! At this point, imagine you want to handle both success/failure case of the `MakeOrder` command processing.
84//! Then you have to think about using event handlers.  
85//!
86//! ## Registering Event
87//!
88//! `Event` is a side effect of [Command] or yet another [Event] processing.
89//! You can register as many handlers as possible as long as they all consume same type of Event as follows:
90//!
91//! ### Example
92//!
93//! ```
94//! # macro_rules! init_event_handler {
95//! #    ($($tt:tt)*) => {}
96//! # }
97//! init_event_handler!(
98//! {
99//!    OrderFaild: [
100//!            NotificationHandler::send_mail,
101//!            ],
102//!    OrderSucceeded: [
103//!            DeliveryHandler::checkout_delivery_items,
104//!            InventoryHandler::change_inventory_count
105//!            ]
106//! }
107//! );
108//! ```
109//! In the `MakeOrder` Command Handling, we have either `OrderFailed` or `OrderSucceeded` event with their own processing handlers.
110//! Events are raised in the handlers that are thrown to [MessageBus] by [Context].
111//! [MessageBus] then loops through the handlers UNLESS `StopSentinel` is received.
112//!
113//! ## Handler API Example
114//!
115//! Handlers can be located anywhere as long as they accept two argument:
116//!
117//! * msg - either [Command] or [Event]
118//! * context - [AtomicContextManager]
119//!
120//! ### Example
121//! ```ignore
122//! pub async fn make_order(
123//!     cmd: MakeOrder,
124//!     context: AtomicContextManager,
125//! ) -> Result<ServiceResponse, ServiceError> {
126//!     let mut uow = UnitOfWork::<Repository<OrderAggregate>, TExecutor>::new(context).await;
127//!
128//!     let mut order_aggregate = OrderAggregate::new(cmd);
129//!     uow.repository().add(&mut task_aggregate).await?;
130//!
131//!     uow.commit::<ServiceOutBox>().await?;
132//!
133//!     Ok(().into())
134//! }
135//! ```
136//! But sometimes, you may want to add yet another dependencies. For that, Dependency Injection mechanism has been implemented.
137//! So, you can also do something along the lines of:
138//! ```ignore
139//! pub async fn make_order(
140//!     cmd: MakeOrder,
141//!     context: AtomicContextManager,
142//!     payment_gateway_caller: Box<dyn Fn(String, Value) -> Future<(), ServiceError> + Send + Sync + 'static> //injected dependency
143//! ) -> Result<ServiceResponse, ServiceError> {
144//!     let mut uow = UnitOfWork::<Repository<OrderAggregate>, TExecutor>::new(context).await;
145//!
146//!     let mut order_aggregate = OrderAggregate::new(cmd,payment_gateway_caller);
147//!     uow.repository().add(&mut task_aggregate).await?;
148//!
149//!     uow.commit::<ServiceOutBox>().await?;
150//!
151//!     Ok(().into())
152//! }
153//! ```
154//!
155//! How is this possible? because we preprocess handlers so it can allow for `DI container`.
156//!
157//! ## Dependency Injection
158//! You can simply register dependencies by putting attribute on top of free function.
159//!
160//! ### Example
161//!
162//! ```ignore
163//! // crate::dependencies
164//! pub fn payment_gateway_caller() -> Box<dyn Fn(String, Value) -> Future<(), ServiceError> + Send + Sync + 'static> {
165//!     if cfg!(test) {
166//!         __test_payment_gateway_caller()  //Dependency For Test
167//!     } else {
168//!         __actual_payment_gateway_caller() //Real Dependency
169//!     }
170//! }
171//! ```
172//!
173//! This is great as you can take your mind off static nature of the language.
174//!
175//!
176//!
177//! ## MessageBus
178//! At the core is event driven library is [MessageBus], which gets command and gets raised event from
179//! `UnitOfWork` and dispatch the event to the right handlers.
180//! As this is done only in framework side, the only way you can 'feel' the presence of messagebus is
181//! when you invoke it. Everything else is done magically.
182//!
183//!
184//!
185//! ### Example
186//! ```ignore
187//! #[derive(Command)]
188//! pub struct MakeOrder { // Test Command
189//!     pub user_id: i64,
190//!     pub items: Vec<String>
191//! }
192//!
193//! async fn test_func(){
194//!     let bus = MessageBus::new(command_handler(), event_handler())
195//!     let command = MakeOrder{user_id:1, items:vec!["shirts","jeans"]}
196//!     match bus.handle(command).await{
197//!         Err(err)=> { // test for error case }
198//!         Ok(val)=> { // test for happy case }
199//!     }
200//!     }
201//!     }
202//! }
203//! ```
204//!
205//! #### Error from MessageBus
206//! When command has not yet been regitered, it returns an error - `BaseError::NotFound`
207//! Be mindful that bus does NOT return the result of event processing as in distributed event processing.
208
209pub extern crate event_driven_core;
210pub extern crate event_driven_macro;
211pub extern crate static_assertions;
212
213pub mod prelude {
214	pub use event_driven_core::event_macros::*;
215	pub use event_driven_core::message::{Aggregate, Command, Message, MessageMetadata};
216	pub use event_driven_core::prelude::*;
217
218	pub use event_driven_macro::{entity, message_handler, Aggregate, ApplicationError, ApplicationResponse, Command, Message};
219}
220
221#[cfg(test)]
222mod application_error_derive_test {
223	use std::fmt::Display;
224
225	use crate as event_driven_library;
226	use event_driven_core::message::Message;
227	use event_driven_core::responses::{AnyError, BaseError};
228	use event_driven_macro::ApplicationError;
229
230	#[derive(Debug, ApplicationError)]
231	#[crates(event_driven_library)]
232	enum Err {
233		#[stop_sentinel]
234		Items,
235		#[stop_sentinel_with_event]
236		StopSentinelWithEvent(Box<dyn Message>),
237		#[database_error]
238		DatabaseError(Box<AnyError>),
239		BaseError(BaseError),
240	}
241
242	impl Display for Err {
243		fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244			match self {
245				Self::Items => write!(f, "items"),
246				Self::StopSentinelWithEvent(item) => write!(f, "{:?}", item),
247				Self::DatabaseError(err) => write!(f, "{:?}", err),
248				Self::BaseError(err) => write!(f, "{:?}", err),
249			}
250		}
251	}
252}