ironflow_engine/config/delay.rs
1//! Configuration for delay (timed pause) steps.
2//!
3//! A [`DelayConfig`] pauses a workflow run for a specified duration.
4//! The worker releases its slot while the run sleeps and resumes
5//! it automatically when the delay elapses.
6
7use std::time::Duration;
8
9use serde::{Deserialize, Serialize};
10
11/// Configuration for a delay step.
12///
13/// The delay is stored as whole seconds for serialization simplicity.
14/// Sub-second precision is not needed for workflow pauses (cooldowns,
15/// rate limiting, scheduled retries).
16///
17/// # Examples
18///
19/// ```
20/// use ironflow_engine::config::delay::DelayConfig;
21///
22/// let config = DelayConfig::from_secs(300);
23/// assert_eq!(config.duration(), std::time::Duration::from_secs(300));
24///
25/// let zero = DelayConfig::from_secs(0);
26/// assert!(zero.is_zero());
27/// ```
28///
29/// # Panics
30///
31/// [`DelayConfig::from_secs`] does not panic. Invalid durations
32/// (negative or overflow) cannot be constructed because the inner
33/// value is `u64`.
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct DelayConfig {
36 /// Delay duration in seconds.
37 duration_secs: u64,
38}
39
40impl DelayConfig {
41 /// Create a delay configuration with the given number of seconds.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use ironflow_engine::config::delay::DelayConfig;
47 ///
48 /// let config = DelayConfig::from_secs(60);
49 /// assert_eq!(config.duration_secs(), 60);
50 /// ```
51 pub fn from_secs(secs: u64) -> Self {
52 Self {
53 duration_secs: secs,
54 }
55 }
56
57 /// The delay duration as a [`Duration`].
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use ironflow_engine::config::delay::DelayConfig;
63 /// use std::time::Duration;
64 ///
65 /// assert_eq!(DelayConfig::from_secs(10).duration(), Duration::from_secs(10));
66 /// ```
67 pub fn duration(&self) -> Duration {
68 Duration::from_secs(self.duration_secs)
69 }
70
71 /// The raw seconds value.
72 pub fn duration_secs(&self) -> u64 {
73 self.duration_secs
74 }
75
76 /// Whether the delay is zero (immediate completion, no sleeping).
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use ironflow_engine::config::delay::DelayConfig;
82 ///
83 /// assert!(DelayConfig::from_secs(0).is_zero());
84 /// assert!(!DelayConfig::from_secs(1).is_zero());
85 /// ```
86 pub fn is_zero(&self) -> bool {
87 self.duration_secs == 0
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn delay_config_from_secs() {
97 let config = DelayConfig::from_secs(300);
98 assert_eq!(config.duration_secs(), 300);
99 assert_eq!(config.duration(), Duration::from_secs(300));
100 assert!(!config.is_zero());
101 }
102
103 #[test]
104 fn delay_config_zero() {
105 let config = DelayConfig::from_secs(0);
106 assert!(config.is_zero());
107 assert_eq!(config.duration(), Duration::ZERO);
108 }
109
110 #[test]
111 fn delay_config_serde_roundtrip() {
112 let config = DelayConfig::from_secs(60);
113 let json = serde_json::to_string(&config).expect("serialize");
114 let back: DelayConfig = serde_json::from_str(&json).expect("deserialize");
115 assert_eq!(config.duration_secs(), back.duration_secs());
116 }
117}