Skip to main content

cronitor_runtime/
lib.rs

1use std::collections::HashMap;
2use std::sync::Mutex;
3use lazy_static::lazy_static;
4use std::thread;
5use std::time::Duration;
6use chrono::prelude::*;
7use colored::*;
8use cron_parser::parse;
9
10lazy_static! {
11    pub static ref CRON_REGISTRY: Mutex<CronRegistry> = Mutex::new(CronRegistry::new());
12}
13
14pub struct CronRegistry {
15    tasks: HashMap<String, (String, fn())>,
16}
17
18impl CronRegistry {
19    pub fn new() -> Self {
20        CronRegistry {
21            tasks: HashMap::new(),
22        }
23    }
24
25    pub fn register(&mut self, name: String, cron_expression: String, task: fn()) {
26        if let Ok(_) = parse(&cron_expression, &Local::now()) {
27            self.tasks.insert(name.clone(), (cron_expression.clone(), task));
28            self.log_next_run(&name, &cron_expression);
29        } else {
30            println!("Invalid cron expression for {}: {}", name.bright_red(), cron_expression.bright_red());
31        }
32    }
33
34    fn log_next_run(&self, name: &str, cron_expression: &str) {
35        println!("Cron expression for {}: {}", name.bright_yellow(), cron_expression);
36        if let Ok(next_run) = parse(cron_expression, &Local::now()) {
37            let now = Local::now();
38            let duration = next_run - now;
39            let hours = duration.num_hours();
40            let minutes = duration.num_minutes() % 60;
41            println!(
42                "{}\n{}\n{}\n{}\n{}\n{}",
43                "+---------------------------------+".bright_blue(),
44                format!("| Current time: {}", now.format("%Y-%m-%d %H:%M:%S")).bright_red(),
45                format!("| Function: {}", name).bright_green(),
46                format!("| Frequency: {}", cron_expression).bright_yellow(),
47                format!("| Next run in: {} hours, {} minutes", hours, minutes).bright_red(),
48                "+---------------------------------+".bright_blue()
49            );
50        } else {
51            println!("Failed to calculate the next run time for {} with expression {}", name.bright_red(), cron_expression.bright_red());
52        }
53    }
54
55    pub fn get_tasks(&self) -> &HashMap<String, (String, fn())> {
56        &self.tasks
57    }
58}
59
60pub fn cron_runtime() {
61    thread::spawn(|| {
62        loop {
63            let tasks: HashMap<String, (String, fn())> = CRON_REGISTRY.lock().unwrap().get_tasks().clone();
64            let now = Local::now();
65
66            for (name, (cron_expression, task)) in tasks {
67                if let Ok(next_run) = parse(&cron_expression, &now.with_timezone(&Utc)) {
68                    let next_run = next_run.with_timezone(&Local);
69
70                    println!(
71                        "Next run for {}: {}",
72                        name.bright_cyan().bold(),
73                        next_run.format("%Y-%m-%d %H:%M:%S").to_string().bold()
74                    );
75
76                    if next_run <= now + chrono::Duration::seconds(60) {
77                        println!("Running task: {}", name.bright_green());
78                        task();
79                    } else {
80                        println!("Task {} not due yet. Next run: {}", name.bright_yellow(), next_run.to_rfc3339());
81                    }
82                } else {
83                    println!("No upcoming run for {}", name.bright_red());
84                }
85            }
86
87            thread::sleep(Duration::from_secs(60));
88        }
89    });
90}