use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct ScheduleSpec {
pub cron: String,
#[serde(default = "default_timezone")]
pub timezone: String,
#[serde(default)]
pub overlap_policy: OverlapPolicy,
#[serde(default)]
pub max_runs: Option<u64>,
#[serde(default)]
pub max_consecutive_failures: Option<u64>,
#[serde(default)]
pub on_failure: ScheduleOnFailure,
#[serde(default)]
pub start_immediately: bool,
#[serde(default)]
pub run_timeout_secs: Option<u64>,
#[serde(default = "default_shutdown_grace_secs")]
pub shutdown_grace_secs: u64,
}
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum OverlapPolicy {
#[default]
Skip,
Queue,
Forbid,
}
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ScheduleOnFailure {
#[default]
Continue,
Stop,
}
fn default_timezone() -> String {
"UTC".to_string()
}
fn default_shutdown_grace_secs() -> u64 {
30
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_apply_when_only_cron_given() {
let spec: ScheduleSpec = serde_yaml::from_str("cron: \"0 2 * * *\"").unwrap();
assert_eq!(spec.cron, "0 2 * * *");
assert_eq!(spec.timezone, "UTC");
assert_eq!(spec.overlap_policy, OverlapPolicy::Skip);
assert_eq!(spec.on_failure, ScheduleOnFailure::Continue);
assert_eq!(spec.max_runs, None);
assert_eq!(spec.max_consecutive_failures, None);
assert!(!spec.start_immediately);
assert_eq!(spec.run_timeout_secs, None);
assert_eq!(spec.shutdown_grace_secs, 30);
}
#[test]
fn enums_use_lowercase_wire_form() {
let spec: ScheduleSpec =
serde_yaml::from_str("cron: \"* * * * *\"\noverlap_policy: queue\non_failure: stop\n")
.unwrap();
assert_eq!(spec.overlap_policy, OverlapPolicy::Queue);
assert_eq!(spec.on_failure, ScheduleOnFailure::Stop);
}
}