diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 56bca6cb08..5bf691ecd7 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1994,6 +1994,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "croner" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b42c74d1c9fc4680c245ca7287bd631fe73eb364657268b0e65bafdec83d47" +dependencies = [ + "chrono", +] + [[package]] name = "crossbeam" version = "0.8.4" @@ -10646,6 +10655,7 @@ dependencies = [ "chrono-tz 0.10.0", "cookie 0.17.0", "cron", + "croner", "datafusion", "futures", "git-version", diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml index b7c4a41aed..eeae1f48de 100644 --- a/backend/windmill-api/Cargo.toml +++ b/backend/windmill-api/Cargo.toml @@ -101,3 +101,4 @@ pin-project.workspace = true http.workspace = true async-stream.workspace = true ulid.workspace = true +croner = "2.0.6" diff --git a/backend/windmill-api/src/schedule.rs b/backend/windmill-api/src/schedule.rs index 7a18976b03..f714761fc0 100644 --- a/backend/windmill-api/src/schedule.rs +++ b/backend/windmill-api/src/schedule.rs @@ -32,6 +32,7 @@ use windmill_common::{ }; use windmill_git_sync::{handle_deployment_metadata, DeployedObject}; use windmill_queue::{schedule::push_scheduled_job, QueueTransaction}; +use croner::Cron; pub fn workspaced_service() -> Router { Router::new() @@ -153,7 +154,11 @@ async fn create_schedule( let mut tx: QueueTransaction<'_, _> = (rsmq.clone(), user_db.begin(&authed).await?).into(); - cron::Schedule::from_str(&ns.schedule).map_err(|e| Error::BadRequest(e.to_string()))?; + Cron::new(&ns.schedule) + .with_seconds_optional() + .parse() + .map_err(|e| Error::BadRequest(format!("cron: {}", e.to_string())))?; + check_path_conflict(tx.transaction_mut(), &w_id, &ns.path).await?; check_flow_conflict( tx.transaction_mut(), @@ -255,7 +260,10 @@ async fn edit_schedule( let mut tx: QueueTransaction<'_, rsmq_async::MultiplexedRsmq> = (rsmq.clone(), user_db.begin(&authed).await?).into(); - cron::Schedule::from_str(&es.schedule).map_err(|e| Error::BadRequest(e.to_string()))?; + Cron::new(&es.schedule) + .with_seconds_optional() + .parse() + .map_err(|e| Error::BadRequest(format!("cron: {}", e.to_string())))?; clear_schedule(tx.transaction_mut(), path, &w_id).await?; let schedule = sqlx::query_as::<_, Schedule>( @@ -468,17 +476,19 @@ pub struct PreviewPayload { pub async fn preview_schedule( Json(payload): Json, ) -> JsonResult>> { - let schedule = cron::Schedule::from_str(&payload.schedule) - .map_err(|e| Error::BadRequest(e.to_string()))?; + + let schedule = Cron::new(&payload.schedule) + .with_seconds_optional() + .parse() + .map_err(|e| Error::BadRequest(format!("cron: {}", e.to_string())))?; let tz = chrono_tz::Tz::from_str(&payload.timezone).map_err(|e| Error::BadRequest(e.to_string()))?; let upcoming: Vec> = schedule - .upcoming(tz) + .iter_from(Utc::now().with_timezone(&tz)) .take(5) - // Convert back to UTC for a standardised API response. The client will convert to the local timezone. - .map(|x| x.with_timezone(&Utc)) + .map(|dt| dt.with_timezone(&Utc)) .collect(); Ok(Json(upcoming))