Skip to content

Commit a8e7043

Browse files
committed
feat: implementation of cron adapter
1 parent 9d625a8 commit a8e7043

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

adapter/cron/src/main.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use async_trait::async_trait;
2+
use base::runner::{ServerContext, ServerRunner};
3+
use base::store::FlowIdentifyResult;
4+
use base::traits::{IdentifiableFlow, LoadConfig, Server};
5+
use chrono::{DateTime, Datelike, Timelike, Utc};
6+
use cron::Schedule;
7+
use std::str::FromStr;
8+
use tucana::shared::ValidationFlow;
9+
use tucana::shared::value::Kind;
10+
11+
#[derive(Default)]
12+
struct Cron {}
13+
14+
#[derive(Clone)]
15+
struct CronConfig {}
16+
17+
impl LoadConfig for CronConfig {
18+
fn load() -> Self {
19+
Self {}
20+
}
21+
}
22+
23+
#[tokio::main]
24+
async fn main() {
25+
let server = Cron::default();
26+
let runner = ServerRunner::new(server).await.unwrap();
27+
runner.serve().await.unwrap();
28+
}
29+
30+
struct Time {
31+
now: DateTime<Utc>,
32+
}
33+
34+
fn extract_flow_setting_field(flow: &ValidationFlow, name: &str) -> Option<String> {
35+
flow.settings
36+
.iter()
37+
.find(|s| s.flow_setting_id == name)
38+
.and_then(|s| s.value.as_ref())
39+
.and_then(|v| v.kind.as_ref())
40+
.and_then(|k| match k {
41+
Kind::StringValue(s) => Some(s.clone()),
42+
_ => None,
43+
})
44+
}
45+
46+
impl IdentifiableFlow for Time {
47+
fn identify(&self, flow: &tucana::shared::ValidationFlow) -> bool {
48+
let Some(minute) = extract_flow_setting_field(&flow, "CRON_MINUTE") else {
49+
return false;
50+
};
51+
let Some(hour) = extract_flow_setting_field(&flow, "CRON_HOUR") else {
52+
return false;
53+
};
54+
let Some(dom) = extract_flow_setting_field(&flow, "CRON_DAY_OF_MONTH") else {
55+
return false;
56+
};
57+
let Some(month) = extract_flow_setting_field(&flow, "CRON_MONTH") else {
58+
return false;
59+
};
60+
let Some(dow) = extract_flow_setting_field(&flow, "CRON_DAY_OF_WEEK") else {
61+
return false;
62+
};
63+
64+
let expression = format!("* {} {} {} {} {}", minute, hour, dom, month, dow);
65+
let schedule = Schedule::from_str(expression.as_str()).unwrap();
66+
let next = schedule.upcoming(Utc).next().unwrap();
67+
68+
self.now.year() == next.year()
69+
&& self.now.month() == next.month()
70+
&& self.now.day() == next.day()
71+
&& self.now.hour() == next.hour()
72+
&& self.now.minute() == next.minute()
73+
}
74+
}
75+
76+
#[async_trait]
77+
impl Server<CronConfig> for Cron {
78+
async fn init(&mut self, _ctx: &ServerContext<CronConfig>) -> anyhow::Result<()> {
79+
Ok(())
80+
}
81+
82+
async fn run(&mut self, ctx: &ServerContext<CronConfig>) -> anyhow::Result<()> {
83+
log::info!("Starting Cron adapter");
84+
let expression = "0 * * * * *";
85+
let schedule = Schedule::from_str(expression)?;
86+
let pattern = "CRON.<";
87+
88+
loop {
89+
let now = Utc::now();
90+
log::info!("Schedlued: {:?}", now);
91+
if let Some(next) = schedule.upcoming(Utc).take(1).next() {
92+
let until_next = next - now;
93+
tokio::time::sleep(until_next.to_std()?).await;
94+
95+
let time = Time { now };
96+
match ctx
97+
.adapter_store
98+
.get_possible_flow_match(pattern.to_string(), time)
99+
.await
100+
{
101+
FlowIdentifyResult::None => {
102+
log::debug!("No Flow identified for this schedule");
103+
}
104+
FlowIdentifyResult::Single(flow) => {
105+
log::debug!("One Flow identified for this schedule");
106+
ctx.adapter_store
107+
.validate_and_execute_flow(flow, None)
108+
.await;
109+
}
110+
FlowIdentifyResult::Multiple(flows) => {
111+
log::debug!("Multiple Flows identified for this schedule");
112+
for flow in flows {
113+
ctx.adapter_store
114+
.validate_and_execute_flow(flow, None)
115+
.await;
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
async fn shutdown(&mut self, _ctx: &ServerContext<CronConfig>) -> anyhow::Result<()> {
124+
Ok(())
125+
}
126+
}
127+

0 commit comments

Comments
 (0)