|
@@ -1,32 +1,50 @@
|
|
|
//! The `jobs` table provides a way to have scheduled jobs
|
|
|
use anyhow::{Result, Context as _};
|
|
|
-use chrono::{DateTime, FixedOffset};
|
|
|
+use chrono::{DateTime, FixedOffset, Duration};
|
|
|
use tokio_postgres::{Client as DbClient};
|
|
|
use uuid::Uuid;
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
+use postgres_types::{ToSql, FromSql};
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
|
pub struct Job {
|
|
|
pub id: Uuid,
|
|
|
pub name: String,
|
|
|
pub expected_time: DateTime<FixedOffset>,
|
|
|
+ pub frequency: Option<i32>,
|
|
|
+ pub frequency_unit: Option<FrequencyUnit>,
|
|
|
pub metadata: serde_json::Value,
|
|
|
pub executed_at: Option<DateTime<FixedOffset>>,
|
|
|
pub error_message: Option<String>,
|
|
|
}
|
|
|
|
|
|
+#[derive(Serialize, Deserialize, Debug, ToSql, FromSql)]
|
|
|
+#[postgres(name = "frequency_unit")]
|
|
|
+pub enum FrequencyUnit {
|
|
|
+ #[postgres(name = "days")]
|
|
|
+ Days,
|
|
|
+ #[postgres(name = "hours")]
|
|
|
+ Hours,
|
|
|
+ #[postgres(name = "minutes")]
|
|
|
+ Minutes,
|
|
|
+ #[postgres(name = "seconds")]
|
|
|
+ Seconds,
|
|
|
+}
|
|
|
+
|
|
|
pub async fn insert_job(
|
|
|
db: &DbClient,
|
|
|
name: &String,
|
|
|
expected_time: &DateTime<FixedOffset>,
|
|
|
+ frequency: &Option<i32>,
|
|
|
+ frequency_unit: &Option<FrequencyUnit>,
|
|
|
metadata: &serde_json::Value
|
|
|
) -> Result<()> {
|
|
|
tracing::trace!("insert_job(name={})", name);
|
|
|
|
|
|
db.execute(
|
|
|
- "INSERT INTO jobs (name, expected_time, metadata) VALUES ($1, $2, $3)
|
|
|
+ "INSERT INTO jobs (name, expected_time, frequency, frequency_unit, metadata) VALUES ($1, $2, $3, $4, $5)
|
|
|
ON CONFLICT (name, expected_time) DO UPDATE SET metadata = EXCLUDED.metadata",
|
|
|
- &[&name, &expected_time, &metadata],
|
|
|
+ &[&name, &expected_time, &frequency, &frequency_unit, &metadata],
|
|
|
)
|
|
|
.await
|
|
|
.context("Inserting job")?;
|
|
@@ -91,19 +109,32 @@ pub async fn get_jobs_to_execute(db: &DbClient) -> Result<Vec<Job>> {
|
|
|
let id: Uuid = job.get(0);
|
|
|
let name: String = job.get(1);
|
|
|
let expected_time: DateTime<FixedOffset> = job.get(2);
|
|
|
- let metadata: serde_json::Value = job.get(3);
|
|
|
- let executed_at: Option<DateTime<FixedOffset>> = job.get(4);
|
|
|
- let error_message: Option<String> = job.get(5);
|
|
|
+ let frequency: Option<i32> = job.get(3);
|
|
|
+ let frequency_unit: Option<FrequencyUnit> = job.get(4);
|
|
|
+ let metadata: serde_json::Value = job.get(5);
|
|
|
+ let executed_at: Option<DateTime<FixedOffset>> = job.get(6);
|
|
|
+ let error_message: Option<String> = job.get(7);
|
|
|
|
|
|
data.push(Job {
|
|
|
id,
|
|
|
name,
|
|
|
expected_time,
|
|
|
- metadata: metadata,
|
|
|
- executed_at: executed_at,
|
|
|
+ frequency,
|
|
|
+ frequency_unit,
|
|
|
+ metadata,
|
|
|
+ executed_at,
|
|
|
error_message
|
|
|
});
|
|
|
}
|
|
|
|
|
|
Ok(data)
|
|
|
}
|
|
|
+
|
|
|
+pub fn get_duration_from_cron(cron_period: i32, cron_unit: &FrequencyUnit) -> Duration {
|
|
|
+ match cron_unit {
|
|
|
+ FrequencyUnit::Days => Duration::days(cron_period as i64),
|
|
|
+ FrequencyUnit::Hours => Duration::hours(cron_period as i64),
|
|
|
+ FrequencyUnit::Minutes => Duration::minutes(cron_period as i64),
|
|
|
+ FrequencyUnit::Seconds => Duration::seconds(cron_period as i64),
|
|
|
+ }
|
|
|
+}
|