ora_util/
schedule.rs

1//! Schedule utilities.
2
3use chrono::TimeZone;
4use ora_common::{
5    schedule::{MissedTasksPolicy, ScheduleDefinition, SchedulePolicy},
6    UnixNanos,
7};
8
9/// Return the next task time for a schedule.
10#[must_use]
11pub fn next_schedule_task(
12    schedule: &ScheduleDefinition,
13    last_task: Option<UnixNanos>,
14    time: UnixNanos,
15) -> Option<UnixNanos> {
16    match last_task {
17        Some(last) => match schedule.missed_tasks {
18            MissedTasksPolicy::Burst => next_from(schedule, last),
19            MissedTasksPolicy::Skip => {
20                let mut next = next_from(schedule, last)?;
21
22                while next < time {
23                    next = next_from(schedule, next)?;
24                }
25
26                Some(next)
27            }
28        },
29        None => {
30            if schedule.immediate {
31                Some(time)
32            } else {
33                next_from(schedule, time)
34            }
35        }
36    }
37}
38
39/// Return the next execution target time from the given point
40/// in time.
41#[allow(clippy::cast_possible_wrap)]
42fn next_from(schedule: &ScheduleDefinition, time: UnixNanos) -> Option<UnixNanos> {
43    match &schedule.policy {
44        SchedulePolicy::Repeat { interval_ns, .. } => Some(UnixNanos(time.0 + interval_ns)),
45        SchedulePolicy::Cron { expr, .. } => {
46            let c: cron::Schedule = match expr.parse() {
47                Ok(c) => c,
48                Err(error) => {
49                    tracing::error!(%error, "invalid cron expression");
50                    return None;
51                }
52            };
53
54            c.after(&chrono::Utc.timestamp_nanos(time.0 as _))
55                .next()
56                .and_then(|t| {
57                    Some(UnixNanos(
58                        t.timestamp_nanos_opt()
59                            .unwrap_or_default()
60                            .try_into()
61                            .ok()?,
62                    ))
63                })
64        }
65    }
66}