actionqueue_core/run/state.rs
1//! Run state definitions for the task execution lifecycle.
2
3/// Canonical states in the run lifecycle.
4///
5/// States progress forward through: Scheduled -> Ready -> Leased -> Running -> (RetryWait -> Ready)* or -> Terminal
6/// A running attempt may also be preempted to Suspended (e.g. by budget exhaustion), then
7/// resumed back to Ready when capacity is restored.
8/// Cancellation is also allowed from Scheduled, Ready, Leased, Running, RetryWait, and Suspended -> Canceled.
9/// Terminal states (Completed, Failed, Canceled) are immutable and cannot transition to any other state.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum RunState {
13 /// The run is scheduled and waiting to become ready.
14 /// Transitions: -> Ready (when scheduled_at has passed), -> Canceled
15 Scheduled,
16
17 /// The run is ready to be leased/ picked up by an executor.
18 /// Transitions: -> Leased (when leased), -> Canceled
19 Ready,
20
21 /// The run has been leased to an executor for processing.
22 /// Transitions: -> Running (when execution starts), -> Ready (lease expired), -> Canceled
23 Leased,
24
25 /// The run is currently being executed.
26 /// Transitions: -> RetryWait (on failure, if retries remain), -> Suspended (preempted),
27 /// -> Completed (on success), -> Failed (on failure, no retries), -> Canceled
28 Running,
29
30 /// The run failed and is waiting before retry.
31 /// Transitions: -> Ready (when backoff completes), -> Failed (if no more retries remain), -> Canceled
32 RetryWait,
33
34 /// The run has been preempted (e.g. budget exhaustion) and is waiting for resumption.
35 /// Non-terminal — will resume to Ready when capacity is restored.
36 /// Suspended attempts do not count toward the max_attempts retry cap.
37 /// Transitions: -> Ready (when budget replenished / explicit resume), -> Canceled
38 Suspended,
39
40 /// The run completed successfully.
41 /// Terminal state - no further transitions allowed.
42 Completed,
43
44 /// The run failed after all retries were exhausted.
45 /// Terminal state - no further transitions allowed.
46 Failed,
47
48 /// The run was canceled.
49 /// Terminal state - no further transitions allowed.
50 Canceled,
51}
52
53impl RunState {
54 /// Returns true if this is a terminal state.
55 pub fn is_terminal(&self) -> bool {
56 matches!(self, RunState::Completed | RunState::Failed | RunState::Canceled)
57 }
58}
59
60impl std::fmt::Display for RunState {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 let name = match self {
63 RunState::Scheduled => "scheduled",
64 RunState::Ready => "ready",
65 RunState::Leased => "leased",
66 RunState::Running => "running",
67 RunState::RetryWait => "retry_wait",
68 RunState::Suspended => "suspended",
69 RunState::Completed => "completed",
70 RunState::Failed => "failed",
71 RunState::Canceled => "canceled",
72 };
73 write!(f, "{name}")
74 }
75}