spring_job/
job.rs

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    /// TODO: tokio-cron-scheduler not support: <https://github.com/mvniekerk/tokio-cron-scheduler/issues/56>
37    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    /// TODO: tokio-cron-scheduler not support: <https://github.com/mvniekerk/tokio-cron-scheduler/issues/56>
62    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            // TODO
92            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}