Skip to main content

reifydb_sub_task/
schedule.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::time::Duration;
5
6use reifydb_runtime::context::clock::Instant;
7
8/// Defines when and how often a task should be executed
9#[derive(Debug, Clone)]
10pub enum Schedule {
11	/// Execute at fixed intervals (interval starts after task completion)
12	FixedInterval(Duration),
13	/// Execute once after a delay
14	Once(Duration),
15}
16
17impl Schedule {
18	/// Calculate the next execution time after the given instant
19	/// Returns None for one-shot tasks
20	pub fn next_execution(&self, after: Instant) -> Option<Instant> {
21		match self {
22			Schedule::FixedInterval(duration) => Some(after + *duration),
23			Schedule::Once(_) => None,
24		}
25	}
26
27	/// Get the initial delay for first execution
28	pub fn initial_delay(&self) -> Duration {
29		match self {
30			Schedule::FixedInterval(duration) => *duration,
31			Schedule::Once(delay) => *delay,
32		}
33	}
34
35	/// Validate the schedule
36	pub fn validate(&self) -> Result<(), String> {
37		match self {
38			Schedule::FixedInterval(duration) => {
39				if duration.is_zero() {
40					return Err("FixedInterval duration cannot be zero".to_string());
41				}
42				Ok(())
43			}
44			Schedule::Once(delay) => {
45				if delay.is_zero() {
46					return Err("Once delay cannot be zero".to_string());
47				}
48				Ok(())
49			}
50		}
51	}
52}
53
54#[cfg(test)]
55mod tests {
56	use reifydb_runtime::context::clock::Clock;
57
58	use super::*;
59
60	#[test]
61	fn test_fixed_interval_next_execution() {
62		let clock = Clock::Real;
63		let schedule = Schedule::FixedInterval(Duration::from_secs(10));
64		let now = clock.instant();
65		let next = schedule.next_execution(now.clone());
66		assert!(next.is_some());
67		assert_eq!(next.unwrap(), now + Duration::from_secs(10));
68	}
69
70	#[test]
71	fn test_once_next_execution() {
72		let clock = Clock::Real;
73		let schedule = Schedule::Once(Duration::from_secs(5));
74		let now = clock.instant();
75		let next = schedule.next_execution(now);
76		assert!(next.is_none());
77	}
78
79	#[test]
80	fn test_initial_delay() {
81		let interval = Schedule::FixedInterval(Duration::from_secs(30));
82		assert_eq!(interval.initial_delay(), Duration::from_secs(30));
83
84		let once = Schedule::Once(Duration::from_secs(5));
85		assert_eq!(once.initial_delay(), Duration::from_secs(5));
86	}
87
88	#[test]
89	fn test_validation() {
90		let valid = Schedule::FixedInterval(Duration::from_secs(1));
91		assert!(valid.validate().is_ok());
92
93		let invalid = Schedule::FixedInterval(Duration::ZERO);
94		assert!(invalid.validate().is_err());
95	}
96}