ora_common/
schedule.rs

1//! Schedules for repeated task executions.
2
3use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use time::Duration;
8
9use crate::task::TaskDefinition;
10
11/// A schedule supports repeatedly spawning jobs
12/// based on the given settings.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14#[must_use]
15pub struct ScheduleDefinition {
16    /// The task schedule policy.
17    pub policy: SchedulePolicy,
18    /// Whether to immediately spawn a task
19    /// when the schedule is first processed.
20    pub immediate: bool,
21    /// The policy for missed tasks.
22    #[serde(default)]
23    pub missed_tasks: MissedTasksPolicy,
24    /// Parameters for newly spawned tasks.
25    pub new_task: NewTask,
26    /// Schedule labels.
27    #[serde(default)]
28    pub labels: HashMap<String, Value>,
29}
30
31impl ScheduleDefinition {
32    /// Create a new schedule.
33    pub fn new(policy: SchedulePolicy, new_task: NewTask) -> Self {
34        Self {
35            missed_tasks: Default::default(),
36            policy,
37            new_task,
38            immediate: false,
39            labels: Default::default(),
40        }
41    }
42
43    /// Set whether a task should be immediately scheduled
44    /// when the schedule is added.
45    pub fn immediate(mut self, immediate: bool) -> Self {
46        self.immediate = immediate;
47        self
48    }
49
50    /// Set the missed tasks policy.
51    pub fn on_missed_tasks(mut self, policy: MissedTasksPolicy) -> Self {
52        self.missed_tasks = policy;
53        self
54    }
55
56    /// Set a label value.
57    ///
58    /// # Panics
59    ///
60    /// Panics if the value is not JSON-serializable.
61    pub fn with_label(mut self, name: &str, value: impl Serialize) -> Self {
62        self.labels
63            .insert(name.into(), serde_json::to_value(value).unwrap());
64        self
65    }
66}
67
68/// Task spawning policy of the schedule.
69///
70/// It is used to configure how and when new
71/// tasks are spawned.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "snake_case")]
74#[must_use]
75pub enum SchedulePolicy {
76    /// Repeatedly spawn tasks.
77    Repeat {
78        /// The interval between tasks.
79        interval_ns: u64,
80    },
81    /// Repeat using a cron expression.
82    Cron {
83        /// A cron expression.
84        expr: String,
85    },
86}
87
88impl SchedulePolicy {
89    /// Repeat tasks with the given interval.
90    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
91    pub fn repeat(interval: Duration) -> Self {
92        Self::Repeat {
93            interval_ns: interval.whole_nanoseconds() as _,
94        }
95    }
96
97    /// Repeat tasks according to the given cron expression.
98    ///
99    /// # Errors
100    ///
101    /// Returns an error if the cron expression is not valid.
102    pub fn cron(expr: &str) -> Result<Self, cron::error::Error> {
103        expr.parse::<cron::Schedule>()?;
104
105        Ok(Self::Cron {
106            expr: expr.to_string(),
107        })
108    }
109}
110
111/// The policy that is used to determine
112/// the execution target time of newly spawned
113/// tasks when the schedule is behind.
114#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
115#[serde(rename_all = "snake_case")]
116pub enum MissedTasksPolicy {
117    /// Queue all missed tasks.
118    Burst,
119    /// Skip all missed tasks and set
120    /// the next task at a multiple of the interval.
121    #[default]
122    Skip,
123}
124
125/// Parameters for newly spawned tasks.
126#[derive(Debug, Clone, Serialize, Deserialize)]
127#[serde(rename_all = "snake_case")]
128pub enum NewTask {
129    /// Spawn the same task repeatedly.
130    Repeat {
131        /// The task to be repeated.
132        task: TaskDefinition,
133    },
134}
135
136impl NewTask {
137    /// Use the same task for each run.
138    #[must_use]
139    pub fn repeat<T>(task: TaskDefinition<T>) -> Self {
140        Self::Repeat { task: task.cast() }
141    }
142}