sz_rust_cli/cmd/
scheduler.rs1use std::sync::Arc;
15
16use clap::Subcommand;
17
18use sz_orm_scheduler::Scheduler;
19
20use crate::error::CliError;
21
22#[derive(Subcommand, Debug)]
24pub enum SchedulerCommand {
25 #[command(name = "list")]
27 List,
28
29 #[command(name = "run")]
31 Run,
32
33 #[command(name = "start")]
35 Start {
36 #[arg(short = 't', long, default_value = "1000")]
38 tick_ms: u64,
39 },
40}
41
42pub fn execute(cmd: &SchedulerCommand) -> Result<(), CliError> {
44 let scheduler = sz_orm_scheduler::CronScheduler::new();
45
46 match cmd {
47 SchedulerCommand::List => execute_list(&scheduler),
48 SchedulerCommand::Run => execute_run(&scheduler),
49 SchedulerCommand::Start { tick_ms } => execute_start(&scheduler, *tick_ms),
50 }
51}
52
53fn execute_list(scheduler: &sz_orm_scheduler::CronScheduler) -> Result<(), CliError> {
55 let tasks = scheduler.list_tasks();
56
57 if tasks.is_empty() {
58 println!("No scheduled tasks registered.");
59 println!();
60 println!("To register tasks, create a scheduler configuration file");
61 println!("or use the scheduler API in your application code.");
62 return Ok(());
63 }
64
65 println!(
66 "{:<15} {:<20} {:<25} {:<8}",
67 "ID", "Name", "Cron", "Enabled"
68 );
69 println!("{}", "-".repeat(70));
70
71 for task in &tasks {
72 println!(
73 "{:<15} {:<20} {:<25} {:<8}",
74 task.id, task.name, task.cron_expr, task.enabled
75 );
76 }
77
78 println!();
79 println!("Total: {} task(s)", tasks.len());
80 Ok(())
81}
82
83fn execute_run(scheduler: &sz_orm_scheduler::CronScheduler) -> Result<(), CliError> {
87 let now = chrono::Utc::now();
88 let fired = scheduler.try_fire_due(now);
89 println!("Scheduler run: {} task(s) fired at {}", fired, now);
90 Ok(())
91}
92
93fn execute_start(
97 scheduler: &sz_orm_scheduler::CronScheduler,
98 tick_ms: u64,
99) -> Result<(), CliError> {
100 println!("Starting scheduler with tick interval: {}ms", tick_ms);
101 println!("Press Ctrl+C to stop.");
102
103 register_demo_tasks(scheduler)?;
105
106 scheduler
108 .start(tick_ms)
109 .map_err(|e| CliError::Scheduler(e.to_string()))?;
110
111 println!("Scheduler started. Waiting for tasks to fire...");
112
113 loop {
116 std::thread::sleep(std::time::Duration::from_secs(1));
117 }
118}
119
120fn register_demo_tasks(scheduler: &sz_orm_scheduler::CronScheduler) -> Result<(), CliError> {
124 let task1 = sz_orm_scheduler::ScheduledTask::new("demo-1", "每分钟任务", "0 * * * *")
126 .with_callback("demo::minute_task");
127 scheduler
128 .schedule(task1)
129 .map_err(|e| CliError::Scheduler(e.to_string()))?;
130
131 let task2 = sz_orm_scheduler::ScheduledTask::new("demo-2", "每小时任务", "0 0 * * *")
133 .with_callback("demo::hourly_task");
134 scheduler
135 .schedule(task2)
136 .map_err(|e| CliError::Scheduler(e.to_string()))?;
137
138 let handler: Arc<dyn sz_orm_scheduler::JobHandler> = Arc::new(DemoJobHandler);
140 scheduler.register_handler("demo-1", handler.clone());
141 scheduler.register_handler("demo-2", handler);
142
143 println!("Registered 2 demo tasks (demo-1, demo-2)");
144 Ok(())
145}
146
147struct DemoJobHandler;
149
150impl sz_orm_scheduler::JobHandler for DemoJobHandler {
151 fn handle(&self, task: &sz_orm_scheduler::ScheduledTask) -> Result<(), String> {
152 println!(
153 "[{}] Task fired: {} ({})",
154 chrono::Utc::now(),
155 task.name,
156 task.id
157 );
158 Ok(())
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use sz_orm_scheduler::JobHandler;
166 use sz_orm_scheduler::Scheduler;
167
168 #[test]
169 fn test_execute_list_empty() {
170 let scheduler = sz_orm_scheduler::CronScheduler::new();
171 let result = execute_list(&scheduler);
172 assert!(result.is_ok());
173 }
174
175 #[test]
176 fn test_execute_list_with_tasks() {
177 let scheduler = sz_orm_scheduler::CronScheduler::new();
178 let task = sz_orm_scheduler::ScheduledTask::new("test-1", "测试任务", "0 * * * *");
179 scheduler.schedule(task).unwrap();
180
181 let result = execute_list(&scheduler);
182 assert!(result.is_ok());
183 }
184
185 #[test]
186 fn test_execute_run() {
187 let scheduler = sz_orm_scheduler::CronScheduler::new();
188 let result = execute_run(&scheduler);
189 assert!(result.is_ok());
190 }
191
192 #[test]
193 fn test_register_demo_tasks() {
194 let scheduler = sz_orm_scheduler::CronScheduler::new();
195 let result = register_demo_tasks(&scheduler);
196 assert!(result.is_ok());
197
198 let tasks = scheduler.list_tasks();
199 assert_eq!(tasks.len(), 2);
200 }
201
202 #[test]
203 fn test_register_demo_tasks_with_invalid_cron() {
204 let scheduler = sz_orm_scheduler::CronScheduler::new();
205 let task = sz_orm_scheduler::ScheduledTask::new("bad", "bad", "");
207 let result = scheduler.schedule(task);
208 assert!(result.is_err());
209 }
210
211 #[test]
212 fn test_demo_job_handler() {
213 let handler = DemoJobHandler;
214 let task = sz_orm_scheduler::ScheduledTask::new("test", "测试", "0 * * * *");
215 let result = handler.handle(&task);
216 assert!(result.is_ok());
217 }
218}