actr_framework/
workload.rs

1//! Workload trait - Executable actor workload
2
3use actr_protocol::{ActorResult, ActrType};
4use async_trait::async_trait;
5
6use crate::{Context, MessageDispatcher};
7
8/// Workload - Executable Actor workload
9///
10/// Represents a complete Actor instance, including:
11/// - Associated dispatcher type (Dispatcher)
12/// - Actor type identifier (actor_type)
13/// - Lifecycle hooks (on_start, on_stop)
14///
15/// # Design Characteristics
16///
17/// - **Bidirectional association**: `Workload::Dispatcher` and `MessageDispatcher::Workload` reference each other
18/// - **Default implementations**: Lifecycle hooks have default no-op implementations, users can optionally override
19/// - **Auto-implementation**: Implemented for wrapper types by code generator
20///
21/// # Code Generation Example
22///
23/// ```rust,ignore
24/// // User-implemented Handler
25/// pub struct MyEchoService { /* ... */ }
26///
27/// impl EchoServiceHandler for MyEchoService {
28///     async fn echo<C: Context>(
29///         &self,
30///         req: EchoRequest,
31///         ctx: &C,
32///     ) -> ActorResult<EchoResponse> {
33///         // Business logic
34///         Ok(EchoResponse { reply: format!("Echo: {}", req.message) })
35///     }
36/// }
37///
38/// // Code-generated Workload wrapper
39/// pub struct EchoServiceWorkload<T: EchoServiceHandler>(pub T);
40///
41/// impl<T: EchoServiceHandler> Workload for EchoServiceWorkload<T> {
42///     type Dispatcher = EchoServiceRouter<T>;
43///
44///     fn actor_type(&self) -> ActrType {
45///         ActrType {
46///             manufacturer: "acme".to_string(),
47///             name: "echo.EchoService".to_string(),
48///         }
49///     }
50/// }
51/// ```
52#[async_trait]
53pub trait Workload: Send + Sync + 'static {
54    /// Associated dispatcher type
55    type Dispatcher: MessageDispatcher<Workload = Self>;
56
57    /// Get Actor type identifier
58    ///
59    /// Used for service discovery and routing.
60    fn actor_type(&self) -> ActrType;
61
62    /// Lifecycle hook: Called when Actor starts
63    ///
64    /// # Default Implementation
65    ///
66    /// Default is a no-op, users can optionally override to perform initialization logic.
67    ///
68    /// # Example
69    ///
70    /// ```rust,ignore
71    /// async fn on_start<C: Context>(&self, ctx: &C) -> ActorResult<()> {
72    ///     tracing::info!("Actor {} started", ctx.self_id());
73    ///     // Initialize resources
74    ///     Ok(())
75    /// }
76    /// ```
77    async fn on_start<C: Context>(&self, _ctx: &C) -> ActorResult<()> {
78        Ok(())
79    }
80
81    /// Lifecycle hook: Called when Actor stops
82    ///
83    /// # Default Implementation
84    ///
85    /// Default is a no-op, users can optionally override to perform cleanup logic.
86    ///
87    /// # Example
88    ///
89    /// ```rust,ignore
90    /// async fn on_stop<C: Context>(&self, ctx: &C) -> ActorResult<()> {
91    ///     tracing::info!("Actor {} stopping", ctx.self_id());
92    ///     // Cleanup resources
93    ///     Ok(())
94    /// }
95    /// ```
96    async fn on_stop<C: Context>(&self, _ctx: &C) -> ActorResult<()> {
97        Ok(())
98    }
99}