tcrm_task/tasks/state.rs
1/// Execution state of a task throughout its lifecycle
2///
3/// `TaskState` tracks the progression of a task from creation through completion.
4/// States transition in a defined order, enabling predictable state management
5/// and event-driven programming.
6///
7/// # State Transitions
8///
9/// ```text
10/// Pending → Initiating → Running → [Ready] → Finished
11/// ↘
12/// → Finished
13/// ```
14///
15/// The Ready state is optional and only occurs for long-running processes
16/// with a configured ready indicator.
17///
18/// # Examples
19///
20/// ## State Monitoring
21/// ```rust
22/// use tcrm_task::tasks::{config::TaskConfig, async_tokio::spawner::TaskSpawner, state::TaskState};
23///
24/// #[tokio::main]
25/// async fn main() {
26/// let config = TaskConfig::new("cmd").args(["/C", "echo", "hello"]);
27/// let spawner = TaskSpawner::new("test".to_string(), config);
28///
29/// // Initially pending
30/// assert_eq!(spawner.get_state().await, TaskState::Pending);
31///
32/// // After calling start_direct(), state will progress through:
33/// // Pending → Initiating → Running → Finished
34/// }
35/// ```
36///
37/// ## Basic State Checking
38/// ```rust
39/// use tcrm_task::tasks::{
40/// config::TaskConfig,
41/// async_tokio::spawner::TaskSpawner,
42/// state::TaskState
43/// };
44///
45/// #[tokio::main]
46/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
47/// let config = TaskConfig::new("cmd").args(["/C", "echo", "hello"]);
48/// let spawner = TaskSpawner::new("demo".to_string(), config);
49///
50/// // Check initial state
51/// let state = spawner.get_state().await;
52/// assert_eq!(state, TaskState::Pending);
53/// println!("Task is in {:?} state", state);
54///
55/// Ok(())
56/// }
57/// ```
58#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
59#[derive(Debug, Clone, PartialEq)]
60pub enum TaskState {
61 /// Task has been created but not yet started
62 ///
63 /// Initial state when `TaskSpawner` is created. The task configuration
64 /// exists but no process has been spawned yet.
65 Pending,
66
67 /// Task is being initialized and validated
68 ///
69 /// Transitional state during `start_direct()` when configuration is being
70 /// validated and the process is being prepared for spawning.
71 Initiating,
72
73 /// Process is running and executing
74 ///
75 /// The system process has been spawned and is actively executing.
76 /// Output events may be emitted during this state.
77 Running,
78
79 /// Process is running and ready to accept requests
80 ///
81 /// Only reached by long-running processes that have a ready indicator
82 /// configured. Indicates the process has completed initialization
83 /// and is ready for work (e.g., web server listening on port).
84 Ready,
85
86 /// Task execution has completed
87 ///
88 /// Final state reached when the process exits normally, is terminated,
89 /// or encounters an error. No further state transitions occur.
90 Finished,
91}
92
93/// Reason for terminating a running task
94///
95/// Provides context about why a task termination was requested,
96/// enabling appropriate cleanup and response handling.
97///
98/// # Examples
99///
100/// ## Timeout Termination
101/// ```rust
102/// use tcrm_task::tasks::{
103/// config::TaskConfig,
104/// async_tokio::spawner::TaskSpawner,
105/// state::TaskTerminateReason
106/// };
107/// use tokio::sync::mpsc;
108///
109/// #[tokio::main]
110/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
111/// let config = TaskConfig::new("cmd").args(["/C", "ping", "127.0.0.1", "-n", "5"]); // 5 second sleep
112/// let mut spawner = TaskSpawner::new("long-task".to_string(), config);
113///
114/// let (tx, _rx) = mpsc::channel(100);
115/// spawner.start_direct(tx).await?;
116///
117/// // Terminate after 1 second
118/// tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
119/// spawner.send_terminate_signal(TaskTerminateReason::Timeout).await?;
120///
121/// Ok(())
122/// }
123/// ```
124///
125/// ## Custom Termination
126/// ```rust
127/// use tcrm_task::tasks::{
128/// config::TaskConfig,
129/// async_tokio::spawner::TaskSpawner,
130/// state::TaskTerminateReason
131/// };
132/// use tokio::sync::mpsc;
133///
134/// #[tokio::main]
135/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
136/// let config = TaskConfig::new("cmd").args(["/C", "echo", "running"]);
137/// let mut spawner = TaskSpawner::new("daemon".to_string(), config);
138///
139/// let (tx, _rx) = mpsc::channel(100);
140/// spawner.start_direct(tx).await?;
141///
142/// // Custom shutdown reason
143/// let reason = TaskTerminateReason::Custom("User requested shutdown".to_string());
144/// spawner.send_terminate_signal(reason).await?;
145///
146/// Ok(())
147/// }
148/// ```
149#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
150#[derive(Debug, Clone, PartialEq)]
151pub enum TaskTerminateReason {
152 /// Task exceeded its configured timeout
153 ///
154 /// The process ran longer than the `timeout_ms` specified in `TaskConfig`
155 /// and was terminated to prevent runaway processes.
156 Timeout,
157
158 /// Task was terminated during cleanup operations
159 ///
160 /// Used when terminating tasks as part of application shutdown,
161 /// resource cleanup, or dependency management.
162 Cleanup,
163
164 /// Task was terminated because its dependencies finished
165 ///
166 /// Used in task orchestration scenarios where tasks depend on
167 /// other tasks and should be terminated when dependencies complete.
168 DependenciesFinished,
169
170 /// Task was terminated for a custom application-specific reason
171 ///
172 /// Allows applications to provide specific context about why
173 /// a task was terminated beyond the standard reasons.
174 Custom(String),
175}