A recipe for building actor systems with minimal boilerplate and good observability.
This project demonstrates a complete actor system implementation in Rust, featuring:
- 80% less boilerplate - Macro-generated client methods with automatic error handling
- Professional observability - Request correlation across actors with timing
- Clean architecture - Domain-specific actors with clear separation of concerns
- Type-safe error handling - Domain-specific error types (UserError, ProductError, OrderError)
- Test-friendly - Test-only messages for inspecting internal actor state
- Production-ready - Error handling, graceful shutdown, and scaling patterns
The system consists of three main actor types:
- UserService - Manages user data (create, get, update, list)
- ProductService - Handles products and inventory (get, check stock, reserve)
- OrderService - Coordinates user and product services to create orders
- OrderSystem - Manages lifecycle, dependency injection, and graceful shutdown
This implementation uses business-friendly terminology:
- Service (e.g.,
UserService) = Actor - Client (e.g.,
UserClient) = Actor Reference/Handle
The client_method! macro eliminates boilerplate for actor communication:
// This generates a complete client method with tracing:
client_method!(UserClient => fn get_user(id: String) -> Option<User> as UserRequest::GetUser);
// Equivalent to writing 15+ lines of boilerplate code manuallyAll operations are automatically traced with structured logging:
INFO user_creation: Creating test user
DEBUG create_user{}: Sending request
DEBUG handle_create_user{user_name="Alice" user_email="alice@example.com"}: Processing create_user request
INFO handle_create_user{user_name="Alice" user_email="alice@example.com"}: User created successfully user_id="user_1"
Multiple patterns for different operation types:
- Sync handlers - Fast, in-memory operations
- Async handlers - I/O operations with validation
- Background handlers - Task owns response channel
- Orchestration handlers - Coordinate multiple sub-actors
# Basic run
cargo run
# With debug logging
RUST_LOG=debug cargo run
# With warning level only
RUST_LOG=warn cargo run// Create the entire order system
let system = OrderSystem::new();
// Create a user (flows to UserService)
let user = User::new("Alice", "alice@example.com");
let user_id = system.user_client.create_user(user).await?;
let order = Order::new("order_1", user_id, "p1", 5, 50.0);
// Process order (orchestrates UserService + ProductService, fails - no products in demo)
match system.order_client.create_order(order).await {
Ok(order_id) => println!("Order created: {}", order_id),
Err(e) => println!("Order failed (expected): {}", e),
}
// Shutdown gracefully
system.shutdown().await?;# Generate and open documentation
cargo doc --opensrc/
└── actor_recipe.rs # Complete implementation with extensive documentation
The single file contains:
- Domain types (User, Product, Order)
- Message enums for typed communication
- Service implementations with tracing
- Client generation macros
- System coordination
- Test-only messages for internal state inspection
- Usage examples and patterns
tokio- Async runtime with full featurestracing- Structured loggingtracing-subscriber- Log formatting and filtering
This is a reference implementation and recipe - use it as a foundation for your own actor systems.