actor_sample/order_actor/mod.rs
1//! # Order Actor
2//!
3//! This module implements the Order resource actor with cross-actor coordination and validation.
4//!
5//! ## Overview
6//!
7//! The Order actor demonstrates the most complex pattern: an actor with **context dependencies**.
8//! It coordinates with User and Product actors to validate orders and reserve inventory during
9//! order creation.
10//!
11//! ## Structure
12//!
13//! - [`entity`] - [`ActorEntity`](actor_framework::ActorEntity) implementation for [`Order`]
14//! - [`error`] - [`OrderError`] type with automatic error conversion from dependencies
15//! - [`new()`] - Factory function that creates the actor and client
16//!
17//! ## Message Flow: create_order
18//!
19//! The following diagram shows how a `create_order` call flows through the system,
20//! demonstrating actor-to-actor communication and validation:
21//!
22//! <div align="center">
23//! <img src="https://raw.githubusercontent.com/schilit/actor-framework-recipe/main/docs/images/create_order_sequence.png" alt="create_order sequence diagram" width="600"/>
24//! </div>
25//!
26//! **Key Points:**
27//! - All communication is asynchronous via message passing
28//! - Each actor processes messages sequentially (no locks needed)
29//! - Validation happens in `Order::on_create()` before the order is stored
30//! - If any step fails, the entire operation fails atomically
31//!
32//! ## Context Dependencies
33//!
34//! The Order actor requires User and Product clients in its context:
35//!
36//! ```rust
37//! use actor_sample::order_actor;
38//! use actor_framework::mock::MockClient;
39//! use actor_sample::clients::{UserClient, ProductClient};
40//! use actor_sample::model::{User, Product};
41//!
42//! #[tokio::main]
43//! async fn main() {
44//! // Create mocks for dependencies
45//! let user_mock = MockClient::<User>::new();
46//! let product_mock = MockClient::<Product>::new();
47//!
48//! let user_client = UserClient::new(user_mock.client());
49//! let product_client = ProductClient::new(product_mock.client());
50//!
51//! // Create actor and client
52//! let (actor, client) = order_actor::new();
53//!
54//! // Start with dependencies injected
55//! tokio::spawn(actor.run((user_client, product_client)));
56//! }
57//! ```
58//!
59//! ## Lifecycle Hooks
60//!
61//! The Order actor uses the `on_create` hook to perform validation and coordination:
62//!
63//! 1. **Validate user exists** - Queries User actor
64//! 2. **Reserve product stock** - Calls Product actor's `reserve_stock` action
65//! 3. **Create order** - Only if validation succeeds
66//!
67//! This ensures orders are always valid and inventory is properly reserved.
68//!
69//! ## Error Handling
70//!
71//! The Order actor demonstrates automatic error conversion with `#[from]`:
72//!
73//! ```rust
74//! use thiserror::Error;
75//! use actor_sample::user_actor::UserError;
76//! use actor_sample::product_actor::ProductError;
77//!
78//! #[derive(Debug, Error)]
79//! pub enum OrderError {
80//! #[error("User service error: {0}")]
81//! UserService(#[from] UserError), // Auto-converts UserError
82//!
83//! #[error("Product service error: {0}")]
84//! ProductService(#[from] ProductError), // Auto-converts ProductError
85//! }
86//! ```
87//!
88//! This allows seamless error propagation from dependency actors.
89//!
90//! ## Key Features
91//!
92//! - **Context injection**: Depends on `(UserClient, ProductClient)`
93//! - **Cross-actor coordination**: Validates and reserves across multiple actors
94//! - **Automatic error conversion**: Uses `#[from]` for clean error handling
95//! - **Lifecycle hooks**: Uses `on_create` for validation logic
96
97pub mod entity;
98pub mod error;
99
100pub use error::*;
101
102use crate::model::Order;
103use actor_framework::{ResourceActor, ResourceClient};
104
105/// Creates a new Order actor and its client.
106pub fn new() -> (ResourceActor<Order>, ResourceClient<Order>) {
107 ResourceActor::new(32)
108}