celery/beat/schedule/
descriptor.rs1use super::{CronSchedule, DeltaSchedule, Schedule};
2use crate::error::ScheduleError;
3use serde::{Deserialize, Serialize};
4use std::time::Duration;
5
6#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
7pub enum ScheduleDescriptor {
8 Cron(CronDescriptor),
9 Delta(DeltaDescriptor),
10}
11
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
13pub struct CronDescriptor {
14 pub minutes: Vec<u32>,
15 pub hours: Vec<u32>,
16 pub month_days: Vec<u32>,
17 pub months: Vec<u32>,
18 pub week_days: Vec<u32>,
19}
20
21#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
22pub struct DeltaDescriptor {
23 pub interval_millis: u64,
24}
25
26impl ScheduleDescriptor {
27 pub fn from_schedule(schedule: &dyn Schedule) -> Option<Self> {
28 schedule.describe()
29 }
30
31 pub fn delta(interval: Duration) -> Self {
32 ScheduleDescriptor::Delta(DeltaDescriptor {
33 interval_millis: interval.as_millis() as u64,
34 })
35 }
36
37 pub fn cron(descriptor: CronDescriptor) -> Self {
38 ScheduleDescriptor::Cron(descriptor)
39 }
40
41 pub fn to_schedule(&self) -> Result<Box<dyn Schedule>, ScheduleError> {
42 match self {
43 ScheduleDescriptor::Delta(desc) => Ok(Box::new(DeltaSchedule::new(
44 Duration::from_millis(desc.interval_millis),
45 ))),
46 ScheduleDescriptor::Cron(desc) => Ok(Box::new(desc.to_schedule()?)),
47 }
48 }
49}
50
51impl CronDescriptor {
52 pub fn to_schedule(&self) -> Result<CronSchedule<chrono::Utc>, ScheduleError> {
53 CronSchedule::new(
54 self.minutes.clone(),
55 self.hours.clone(),
56 self.month_days.clone(),
57 self.months.clone(),
58 self.week_days.clone(),
59 )
60 }
61}
62
63impl DeltaDescriptor {
64 pub fn interval(&self) -> Duration {
65 Duration::from_millis(self.interval_millis)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn delta_descriptor_roundtrip() {
75 let schedule = DeltaSchedule::new(Duration::from_millis(250));
76 let descriptor = ScheduleDescriptor::from_schedule(&schedule).expect("descriptor");
77
78 let restored = descriptor.to_schedule().expect("restored");
79 let next_original = schedule.next_call_at(None).unwrap();
80 let next_restored = restored.next_call_at(None).unwrap();
81
82 assert!(
83 next_restored
84 .duration_since(next_original)
85 .unwrap_or_else(|_| Duration::from_secs(0))
86 < Duration::from_millis(2)
87 );
88 }
89
90 #[test]
91 fn cron_descriptor_roundtrip() {
92 let cron = CronSchedule::from_string("*/5 * * * *").expect("cron");
93 let descriptor = ScheduleDescriptor::from_schedule(&cron).expect("descriptor");
94
95 let restored = descriptor.to_schedule().expect("restored");
96 let next_original = cron.next_call_at(None).unwrap();
97 let next_restored = restored.next_call_at(None).unwrap();
98
99 assert!(
100 next_restored
101 .duration_since(next_original)
102 .unwrap_or_else(|_| Duration::from_secs(0))
103 < Duration::from_secs(60)
104 );
105 }
106}