|
1 | 1 | //! The `jobs` table provides a way to have scheduled jobs
|
2 | 2 | use anyhow::{Result, Context as _};
|
3 |
| -use chrono::{DateTime, FixedOffset}; |
| 3 | +use chrono::{DateTime, FixedOffset, Duration}; |
4 | 4 | use tokio_postgres::{Client as DbClient};
|
5 | 5 | use uuid::Uuid;
|
6 | 6 | use serde::{Deserialize, Serialize};
|
| 7 | +use postgres_types::{ToSql, FromSql}; |
7 | 8 |
|
8 | 9 | #[derive(Serialize, Deserialize, Debug)]
|
9 | 10 | pub struct Job {
|
10 | 11 | pub id: Uuid,
|
11 | 12 | pub name: String,
|
12 | 13 | pub expected_time: DateTime<FixedOffset>,
|
| 14 | + pub frequency: Option<i32>, |
| 15 | + pub frequency_unit: Option<FrequencyUnit>, |
13 | 16 | pub metadata: serde_json::Value,
|
14 | 17 | pub executed_at: Option<DateTime<FixedOffset>>,
|
15 | 18 | pub error_message: Option<String>,
|
16 | 19 | }
|
17 | 20 |
|
| 21 | +#[derive(Serialize, Deserialize, Debug, ToSql, FromSql)] |
| 22 | +#[postgres(name = "frequency_unit")] |
| 23 | +pub enum FrequencyUnit { |
| 24 | + #[postgres(name = "days")] |
| 25 | + Days, |
| 26 | + #[postgres(name = "hours")] |
| 27 | + Hours, |
| 28 | + #[postgres(name = "minutes")] |
| 29 | + Minutes, |
| 30 | + #[postgres(name = "seconds")] |
| 31 | + Seconds, |
| 32 | +} |
| 33 | + |
18 | 34 | pub async fn insert_job(
|
19 | 35 | db: &DbClient,
|
20 | 36 | name: &String,
|
21 | 37 | expected_time: &DateTime<FixedOffset>,
|
| 38 | + frequency: &Option<i32>, |
| 39 | + frequency_unit: &Option<FrequencyUnit>, |
22 | 40 | metadata: &serde_json::Value
|
23 | 41 | ) -> Result<()> {
|
24 | 42 | tracing::trace!("insert_job(name={})", name);
|
25 | 43 |
|
26 | 44 | db.execute(
|
27 |
| - "INSERT INTO jobs (name, expected_time, metadata) VALUES ($1, $2, $3) |
| 45 | + "INSERT INTO jobs (name, expected_time, frequency, frequency_unit, metadata) VALUES ($1, $2, $3, $4, $5) |
28 | 46 | ON CONFLICT (name, expected_time) DO UPDATE SET metadata = EXCLUDED.metadata",
|
29 |
| - &[&name, &expected_time, &metadata], |
| 47 | + &[&name, &expected_time, &frequency, &frequency_unit, &metadata], |
30 | 48 | )
|
31 | 49 | .await
|
32 | 50 | .context("Inserting job")?;
|
@@ -91,19 +109,32 @@ pub async fn get_jobs_to_execute(db: &DbClient) -> Result<Vec<Job>> {
|
91 | 109 | let id: Uuid = job.get(0);
|
92 | 110 | let name: String = job.get(1);
|
93 | 111 | let expected_time: DateTime<FixedOffset> = job.get(2);
|
94 |
| - let metadata: serde_json::Value = job.get(3); |
95 |
| - let executed_at: Option<DateTime<FixedOffset>> = job.get(4); |
96 |
| - let error_message: Option<String> = job.get(5); |
| 112 | + let frequency: Option<i32> = job.get(3); |
| 113 | + let frequency_unit: Option<FrequencyUnit> = job.get(4); |
| 114 | + let metadata: serde_json::Value = job.get(5); |
| 115 | + let executed_at: Option<DateTime<FixedOffset>> = job.get(6); |
| 116 | + let error_message: Option<String> = job.get(7); |
97 | 117 |
|
98 | 118 | data.push(Job {
|
99 | 119 | id,
|
100 | 120 | name,
|
101 | 121 | expected_time,
|
102 |
| - metadata: metadata, |
103 |
| - executed_at: executed_at, |
| 122 | + frequency, |
| 123 | + frequency_unit, |
| 124 | + metadata, |
| 125 | + executed_at, |
104 | 126 | error_message
|
105 | 127 | });
|
106 | 128 | }
|
107 | 129 |
|
108 | 130 | Ok(data)
|
109 | 131 | }
|
| 132 | + |
| 133 | +pub fn get_duration_from_cron(cron_period: i32, cron_unit: &FrequencyUnit) -> Duration { |
| 134 | + match cron_unit { |
| 135 | + FrequencyUnit::Days => Duration::days(cron_period as i64), |
| 136 | + FrequencyUnit::Hours => Duration::hours(cron_period as i64), |
| 137 | + FrequencyUnit::Minutes => Duration::minutes(cron_period as i64), |
| 138 | + FrequencyUnit::Seconds => Duration::seconds(cron_period as i64), |
| 139 | + } |
| 140 | +} |
0 commit comments