1use crate::{
2 handler::{BoxedHandler, Handler},
3 JobId, JobScheduler,
4};
5use serde::Serialize;
6use spring::app::App;
7use std::{sync::Arc, time::Duration};
8
9#[derive(Clone)]
10enum Trigger {
11 OneShot(u64),
12 FixedDelay(u64),
13 FixedRate(u64),
14 Cron(String),
15}
16
17#[derive(Clone)]
18pub struct Job {
19 trigger: Trigger,
20 handler: BoxedHandler,
21 extra: Option<Vec<u8>>,
22}
23
24pub struct JobBuilder<T: Serialize = ()> {
25 trigger: Trigger,
26 data: Option<T>,
27}
28
29impl Job {
30 pub fn one_shot(delay_seconds: u64) -> JobBuilder {
31 JobBuilder {
32 trigger: Trigger::OneShot(delay_seconds),
33 data: None,
34 }
35 }
36 pub fn fix_delay(seconds: u64) -> JobBuilder {
38 JobBuilder {
39 trigger: Trigger::FixedDelay(seconds),
40 data: None,
41 }
42 }
43 pub fn fix_rate(seconds: u64) -> JobBuilder {
44 JobBuilder {
45 trigger: Trigger::FixedRate(seconds),
46 data: None,
47 }
48 }
49 pub fn cron(cron: &str) -> JobBuilder {
50 JobBuilder {
51 trigger: Trigger::Cron(cron.to_string()),
52 data: None,
53 }
54 }
55 pub fn one_shot_with_data<T: Serialize>(delay_seconds: u64, data: T) -> JobBuilder<T> {
56 JobBuilder {
57 trigger: Trigger::OneShot(delay_seconds),
58 data: Some(data),
59 }
60 }
61 pub fn fix_delay_with_data<T: Serialize>(seconds: u64, data: T) -> JobBuilder<T> {
63 JobBuilder {
64 trigger: Trigger::FixedDelay(seconds),
65 data: Some(data),
66 }
67 }
68 pub fn fix_rate_with_data<T: Serialize>(seconds: u64, data: T) -> JobBuilder<T> {
69 JobBuilder {
70 trigger: Trigger::FixedRate(seconds),
71 data: Some(data),
72 }
73 }
74 pub fn cron_with_data<T: Serialize>(cron: &str, data: T) -> JobBuilder<T> {
75 JobBuilder {
76 trigger: Trigger::Cron(cron.to_string()),
77 data: Some(data),
78 }
79 }
80 pub fn build(self, app: Arc<App>) -> tokio_cron_scheduler::Job {
81 let handler = self.handler;
82 let mut job = match self.trigger {
83 Trigger::OneShot(seconds) => tokio_cron_scheduler::Job::new_one_shot_async(
84 Duration::from_secs(seconds),
85 move |job_id, jobs| {
86 let handler = handler.clone();
87 let app = app.clone();
88 Box::pin(async move { handler.call(job_id, jobs, app).await })
89 },
90 ),
91 Trigger::FixedDelay(seconds) => tokio_cron_scheduler::Job::new_repeated_async(
93 Duration::from_secs(seconds),
94 move |job_id, jobs| {
95 Box::pin(Self::call(handler.clone(), job_id, jobs, app.clone()))
96 },
97 ),
98 Trigger::FixedRate(seconds) => tokio_cron_scheduler::Job::new_repeated_async(
99 Duration::from_secs(seconds),
100 move |job_id, jobs| {
101 Box::pin(Self::call(handler.clone(), job_id, jobs, app.clone()))
102 },
103 ),
104 Trigger::Cron(schedule) => tokio_cron_scheduler::Job::new_async_tz(
105 schedule.as_str(),
106 chrono::Local,
107 move |job_id, jobs| {
108 Box::pin(Self::call(handler.clone(), job_id, jobs, app.clone()))
109 },
110 ),
111 }
112 .expect("build job failed");
113 if let Some(extra) = self.extra {
114 let mut data = job.job_data().expect("get job_data failed");
115 data.extra = extra;
116 job.set_job_data(data).expect("set job_data failed");
117 }
118 job
119 }
120
121 async fn call(handler: BoxedHandler, job_id: JobId, jobs: JobScheduler, app: Arc<App>) {
122 handler.call(job_id, jobs, app).await
123 }
124}
125
126impl<T: Serialize> JobBuilder<T> {
127 pub fn run<H, A>(self, handler: H) -> Job
128 where
129 H: Handler<A> + Sync,
130 A: 'static,
131 {
132 Job {
133 trigger: self.trigger,
134 handler: BoxedHandler::from_handler(handler),
135 extra: self
136 .data
137 .map(|data| serde_json::to_vec(&data).expect("job data to json failed")),
138 }
139 }
140}