forge_core/cron/
context.rs1use chrono::{DateTime, Utc};
2use uuid::Uuid;
3
4use crate::function::AuthContext;
5
6pub struct CronContext {
8 pub run_id: Uuid,
10 pub cron_name: String,
12 pub scheduled_time: DateTime<Utc>,
14 pub execution_time: DateTime<Utc>,
16 pub timezone: String,
18 pub is_catch_up: bool,
20 pub auth: AuthContext,
22 db_pool: sqlx::PgPool,
24 http_client: reqwest::Client,
26 pub log: CronLog,
28}
29
30impl CronContext {
31 pub fn new(
33 run_id: Uuid,
34 cron_name: String,
35 scheduled_time: DateTime<Utc>,
36 timezone: String,
37 is_catch_up: bool,
38 db_pool: sqlx::PgPool,
39 http_client: reqwest::Client,
40 ) -> Self {
41 Self {
42 run_id,
43 cron_name: cron_name.clone(),
44 scheduled_time,
45 execution_time: Utc::now(),
46 timezone,
47 is_catch_up,
48 auth: AuthContext::unauthenticated(),
49 db_pool,
50 http_client,
51 log: CronLog::new(cron_name),
52 }
53 }
54
55 pub fn db(&self) -> &sqlx::PgPool {
57 &self.db_pool
58 }
59
60 pub fn http(&self) -> &reqwest::Client {
62 &self.http_client
63 }
64
65 pub fn delay(&self) -> chrono::Duration {
67 self.execution_time - self.scheduled_time
68 }
69
70 pub fn is_late(&self) -> bool {
72 self.delay() > chrono::Duration::minutes(1)
73 }
74
75 pub fn with_auth(mut self, auth: AuthContext) -> Self {
77 self.auth = auth;
78 self
79 }
80}
81
82#[derive(Clone)]
84pub struct CronLog {
85 cron_name: String,
86}
87
88impl CronLog {
89 pub fn new(cron_name: String) -> Self {
91 Self { cron_name }
92 }
93
94 pub fn info(&self, message: &str, data: serde_json::Value) {
96 tracing::info!(
97 cron_name = %self.cron_name,
98 data = %data,
99 "{}",
100 message
101 );
102 }
103
104 pub fn warn(&self, message: &str, data: serde_json::Value) {
106 tracing::warn!(
107 cron_name = %self.cron_name,
108 data = %data,
109 "{}",
110 message
111 );
112 }
113
114 pub fn error(&self, message: &str, data: serde_json::Value) {
116 tracing::error!(
117 cron_name = %self.cron_name,
118 data = %data,
119 "{}",
120 message
121 );
122 }
123
124 pub fn debug(&self, message: &str, data: serde_json::Value) {
126 tracing::debug!(
127 cron_name = %self.cron_name,
128 data = %data,
129 "{}",
130 message
131 );
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[tokio::test]
140 async fn test_cron_context_creation() {
141 let pool = sqlx::postgres::PgPoolOptions::new()
142 .max_connections(1)
143 .connect_lazy("postgres://localhost/nonexistent")
144 .expect("Failed to create mock pool");
145
146 let run_id = Uuid::new_v4();
147 let scheduled = Utc::now() - chrono::Duration::seconds(30);
148
149 let ctx = CronContext::new(
150 run_id,
151 "test_cron".to_string(),
152 scheduled,
153 "UTC".to_string(),
154 false,
155 pool,
156 reqwest::Client::new(),
157 );
158
159 assert_eq!(ctx.run_id, run_id);
160 assert_eq!(ctx.cron_name, "test_cron");
161 assert!(!ctx.is_catch_up);
162 }
163
164 #[tokio::test]
165 async fn test_cron_delay() {
166 let pool = sqlx::postgres::PgPoolOptions::new()
167 .max_connections(1)
168 .connect_lazy("postgres://localhost/nonexistent")
169 .expect("Failed to create mock pool");
170
171 let scheduled = Utc::now() - chrono::Duration::minutes(5);
172
173 let ctx = CronContext::new(
174 Uuid::new_v4(),
175 "test_cron".to_string(),
176 scheduled,
177 "UTC".to_string(),
178 false,
179 pool,
180 reqwest::Client::new(),
181 );
182
183 assert!(ctx.is_late());
184 assert!(ctx.delay() >= chrono::Duration::minutes(5));
185 }
186
187 #[test]
188 fn test_cron_log() {
189 let log = CronLog::new("test_cron".to_string());
190 log.info("Test message", serde_json::json!({"key": "value"}));
191 }
192}