Skip to main content

actionqueue_core/
subscription.rs

1//! Subscription domain types for event-driven task promotion.
2//!
3//! Subscriptions allow tasks to be promoted to Ready when specific events
4//! occur — task completion, run state changes, budget threshold crossings,
5//! or application-defined custom events. The dispatch loop evaluates active
6//! subscriptions each tick and triggers those whose filters match.
7
8use std::fmt::{Display, Formatter};
9use std::str::FromStr;
10
11use uuid::Uuid;
12
13use crate::budget::BudgetDimension;
14use crate::ids::TaskId;
15use crate::run::state::RunState;
16
17/// A unique identifier for an event subscription.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct SubscriptionId(Uuid);
21
22impl SubscriptionId {
23    /// Creates a new random SubscriptionId.
24    pub fn new() -> Self {
25        SubscriptionId(Uuid::new_v4())
26    }
27
28    /// Creates a SubscriptionId from a UUID.
29    pub fn from_uuid(uuid: Uuid) -> Self {
30        SubscriptionId(uuid)
31    }
32
33    /// Returns the inner UUID.
34    pub fn as_uuid(&self) -> &Uuid {
35        &self.0
36    }
37}
38
39impl Default for SubscriptionId {
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45impl FromStr for SubscriptionId {
46    type Err = uuid::Error;
47
48    fn from_str(s: &str) -> Result<Self, Self::Err> {
49        Uuid::from_str(s).map(SubscriptionId)
50    }
51}
52
53impl Display for SubscriptionId {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        write!(f, "{}", self.0)
56    }
57}
58
59/// A filter that specifies which events trigger a subscription.
60///
61/// Subscriptions are evaluated each tick against the set of events that
62/// occurred during that tick. A matching subscription triggers the
63/// subscribing task's scheduled run to be promoted to Ready.
64#[derive(Debug, Clone, PartialEq, Eq)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66pub enum EventFilter {
67    /// Fires when a specific task reaches terminal success (Completed).
68    TaskCompleted {
69        /// The task that must complete to trigger this subscription.
70        task_id: TaskId,
71    },
72    /// Fires when any run of a specific task transitions to the given state.
73    RunStateChanged {
74        /// The task to observe.
75        task_id: TaskId,
76        /// The target run state that triggers this subscription.
77        state: RunState,
78    },
79    /// Fires when a task's budget consumption crosses a percentage threshold.
80    BudgetThreshold {
81        /// The task whose budget is observed.
82        task_id: TaskId,
83        /// The budget dimension to observe.
84        dimension: BudgetDimension,
85        /// The consumption percentage (0-100) at which to trigger.
86        threshold_pct: u8,
87    },
88    /// Fires when an application-defined event with this key is emitted.
89    Custom {
90        /// The application-defined event key.
91        key: String,
92    },
93}