ora_client/
schedule_definition.rs

1//! Schedule definitions and details.
2
3use std::time::{Duration, SystemTime};
4
5use serde::Serialize;
6use uuid::Uuid;
7
8use crate::{IndexMap, JobDefinition};
9
10/// A new schedule.
11#[derive(Debug, Clone)]
12#[must_use]
13pub struct ScheduleDefinition {
14    /// Scheduling policy for the schedule.
15    pub job_timing_policy: ScheduleJobTimingPolicy,
16    /// Policy for new jobs created by the schedule.
17    pub job_creation_policy: ScheduleJobCreationPolicy,
18    /// Labels of the schedule.
19    pub labels: IndexMap<String, String>,
20    /// The time range for the schedule.
21    ///
22    /// The schedule must not start before `start` and must end before `end`.
23    pub time_range: Option<ScheduleTimeRange>,
24    /// Arbitrary metadata in JSON format.
25    pub metadata_json: Option<String>,
26    /// Whether to copy schedule labels to created jobs.
27    ///
28    /// Labels are not overwritten if they already exist on the job.
29    ///
30    /// Note that this is a client-side operation
31    /// that is done before the schedule is submitted to the server
32    /// for creation.
33    ///
34    /// By default, this is `true`.
35    pub propagate_labels_to_jobs: bool,
36}
37
38impl ScheduleDefinition {
39    /// Set the schedule to immediately create a job when started.
40    ///
41    /// This is a no-op for timing policies that do not support it.
42    pub fn immediate(mut self) -> Self {
43        match &mut self.job_timing_policy {
44            ScheduleJobTimingPolicy::Repeat(policy) => policy.immediate = true,
45            ScheduleJobTimingPolicy::Cron(policy) => policy.immediate = true,
46        }
47        self
48    }
49
50    /// Set a start time for the schedule.
51    pub fn start_after(mut self, start: SystemTime) -> Self {
52        if let Some(time_range) = self.time_range.as_mut() {
53            time_range.start = Some(start);
54        } else {
55            self.time_range = Some(ScheduleTimeRange {
56                start: Some(start),
57                end: None,
58            });
59        }
60        self
61    }
62
63    /// Set an end time for the schedule.
64    pub fn end_before(mut self, end: SystemTime) -> Self {
65        if let Some(time_range) = self.time_range.as_mut() {
66            time_range.end = Some(end);
67        } else {
68            self.time_range = Some(ScheduleTimeRange {
69                start: None,
70                end: Some(end),
71            });
72        }
73        self
74    }
75
76    /// Add a label to the schedule.
77    ///
78    /// Note that this will not set any labels
79    /// for jobs created by the schedule.
80    pub fn with_label(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
81        self.labels.insert(key.into(), value.into());
82        self
83    }
84
85    /// Add a JSON label to the schedule.
86    ///
87    /// # Panics
88    ///
89    /// If the value cannot be serialized to JSON.
90    pub fn with_label_json(mut self, key: impl Into<String>, value: impl Serialize) -> Self {
91        self.labels.insert(
92            key.into(),
93            serde_json::to_string(&value).expect("label serialization failed"),
94        );
95        self
96    }
97
98    /// Set additional metadata for the schedule.
99    ///
100    /// Note that this will replace any existing metadata.
101    ///
102    /// # Panics
103    ///
104    /// If the metadata cannot be serialized to JSON.
105    pub fn replace_metadata(mut self, metadata: impl Serialize) -> Self {
106        self.metadata_json =
107            Some(serde_json::to_string(&metadata).expect("metadata serialization failed"));
108        self
109    }
110
111    /// Whether to propagate schedule labels to created jobs.
112    ///
113    /// Labels are not overwritten if they already exist on the job.
114    ///
115    /// Note that this is a client-side operation
116    /// that is done before the schedule is submitted to the server
117    /// for creation.
118    ///
119    /// By default, this is `true`.
120    pub fn propagate_labels(mut self, propagate: bool) -> Self {
121        self.propagate_labels_to_jobs = propagate;
122        self
123    }
124}
125
126/// Scheduling policy for a schedule.
127#[derive(Debug, Clone)]
128pub enum ScheduleJobTimingPolicy {
129    /// A schedule that repeats.
130    Repeat(ScheduleJobTimingPolicyRepeat),
131    /// A schedule based on a cron expression.
132    Cron(ScheduleJobTimingPolicyCron),
133}
134
135/// Scheduling policy for a schedule that repeats.
136#[derive(Debug, Clone)]
137pub struct ScheduleJobTimingPolicyRepeat {
138    /// The interval between each job.
139    pub interval: Duration,
140    /// Whether the schedule should create a job immediately.
141    pub immediate: bool,
142    /// The policy for missed jobs.
143    pub missed_time_policy: ScheduleMissedTimePolicy,
144}
145
146/// Scheduling policy based on a cron expression.
147#[derive(Debug, Clone)]
148pub struct ScheduleJobTimingPolicyCron {
149    /// The cron expression.
150    pub cron_expression: String,
151    /// Whether the schedule should create a job immediately.
152    pub immediate: bool,
153    /// The policy for missed jobs.
154    pub missed_time_policy: ScheduleMissedTimePolicy,
155}
156
157/// Policy for missed jobs.
158#[derive(Debug, Default, Clone, Copy)]
159pub enum ScheduleMissedTimePolicy {
160    /// Skip any missed times.
161    #[default]
162    Skip,
163    /// Create a job for each missed time.
164    Create,
165}
166
167/// Policy for new jobs created by a schedule.
168#[derive(Debug, Clone)]
169pub enum ScheduleJobCreationPolicy {
170    /// Create a new job from the given job definition.
171    JobDefinition(JobDefinition),
172}
173
174/// The time range for a schedule.
175#[derive(Debug, Clone, Copy)]
176pub struct ScheduleTimeRange {
177    /// The schedule must not start before this time.
178    pub start: Option<SystemTime>,
179    /// The schedule must end before this time.
180    pub end: Option<SystemTime>,
181}
182
183/// Details of a schedule.
184///
185/// Associated jobs are not included on purpose
186/// as there can be many jobs associated with a schedule,
187/// additional queries can be made to get the jobs.
188#[derive(Debug, Clone)]
189pub struct ScheduleDetails {
190    /// The unique identifier of the schedule.
191    pub id: Uuid,
192    /// The time the schedule was created.
193    pub created_at: SystemTime,
194    /// Scheduling policy for the schedule.
195    pub job_timing_policy: ScheduleJobTimingPolicy,
196    /// Policy for new jobs created by the schedule.
197    pub job_creation_policy: ScheduleJobCreationPolicy,
198    /// Labels of the schedule.
199    pub labels: IndexMap<String, String>,
200    /// Whether the schedule is active.
201    pub active: bool,
202    /// Whether the schedule was cancelled.
203    pub cancelled: bool,
204    /// The time range for the schedule.
205    pub time_range: Option<ScheduleTimeRange>,
206    /// Arbitrary metadata in JSON format.
207    pub metadata_json: Option<String>,
208}