From 2eeaf5639dfcdb0114dc5fc323dbd10ef5ceaca5 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sat, 20 Sep 2025 11:29:35 +0000 Subject: [PATCH] feat: force cancel in batch cancel --- backend/windmill-api/openapi.yaml | 4 ++ backend/windmill-api/src/jobs.rs | 18 +++++++- .../(logged)/runs/[...path]/+page.svelte | 42 +++++++++++++++---- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index cc7940715c..dd3dcb5893 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -7727,6 +7727,10 @@ paths: - job parameters: - $ref: "#/components/parameters/WorkspaceId" + - name: force_cancel + in: query + schema: + type: boolean requestBody: description: uuids of the jobs to cancel required: true diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 1b75070217..8089e39fda 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -2055,6 +2055,7 @@ async fn cancel_jobs( db: &DB, username: &str, w_id: &str, + force_cancel: bool, ) -> error::JsonResult> { let mut uuids = vec![]; let mut tx = db.begin().await?; @@ -2114,7 +2115,7 @@ async fn cancel_jobs( w_id, tx, db, - false, + force_cancel, false, ) .await?; @@ -2145,11 +2146,17 @@ async fn cancel_jobs( Ok(Json(uuids)) } +#[derive(Deserialize)] +pub struct CancelSelectionQuery { + force_cancel: Option, +} + async fn cancel_selection( authed: ApiAuthed, Extension(db): Extension, Extension(user_db): Extension, Path(w_id): Path, + Query(query): Query, Json(jobs): Json>, ) -> error::JsonResult> { let mut tx = user_db.begin(&authed).await?; @@ -2163,7 +2170,14 @@ async fn cancel_selection( .await?; tx.commit().await?; - cancel_jobs(jobs_to_cancel, &db, authed.username.as_str(), w_id.as_str()).await + cancel_jobs( + jobs_to_cancel, + &db, + authed.username.as_str(), + w_id.as_str(), + query.force_cancel.unwrap_or(false), + ) + .await } async fn list_filtered_job_uuids( diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte index ec50dab88c..153d8772ef 100644 --- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte @@ -186,7 +186,7 @@ confirmBtnText: string loading?: boolean preContent?: string - onConfirm?: () => void + onConfirm?: (forceCancel: boolean) => void type?: ConfirmationModal['$$prop_def']['type'] } = $state(undefined) @@ -544,10 +544,11 @@ } } - async function cancelJobs(uuidsToCancel: string[]) { + async function cancelJobs(uuidsToCancel: string[], forceCancel: boolean = false) { const uuids = await JobService.cancelSelection({ workspace: $workspaceStore ?? '', - requestBody: uuidsToCancel + requestBody: uuidsToCancel, + forceCancel: forceCancel }) selectedIds = [] jobsLoader?.loadJobs(minTs, maxTs, true, true) @@ -556,6 +557,7 @@ } async function onCancelFilteredJobs() { + forceCancelInPopup = false askingForConfirmation = { title: 'Confirm cancelling all jobs corresponding to the selected filters', confirmBtnText: 'Loading...', @@ -570,18 +572,19 @@ title: `Confirm cancelling all jobs corresponding to the selected filters (${jobIdsToCancel.length} jobs)`, confirmBtnText: `Cancel ${jobIdsToCancel.length} jobs that matched the filters`, preContent: selectedFiltersString, - onConfirm: () => { - cancelJobs(jobIdsToCancel) + onConfirm: (forceCancel) => { + cancelJobs(jobIdsToCancel, forceCancel) } } } async function onCancelSelectedJobs() { + forceCancelInPopup = true askingForConfirmation = { confirmBtnText: `Cancel ${selectedIds.length} jobs`, title: 'Confirm cancelling the selected jobs', - onConfirm: () => { - cancelJobs(selectedIds) + onConfirm: (forceCancel) => { + cancelJobs(selectedIds, forceCancel) } } } @@ -798,6 +801,8 @@ const smallScreenWidth = 1920 const verySmallScreenWidth = 1300 + + let forceCancelInPopup = $state(false) { const func = askingForConfirmation?.onConfirm - await func?.() + await func?.(forceCancelInPopup) askingForConfirmation = undefined }} type={askingForConfirmation?.type} @@ -853,6 +858,27 @@ > {#if askingForConfirmation?.preContent}
{askingForConfirmation.preContent}
+ + {#if forceCancelInPopup} +
+

+ Force cancel is enabled. This is dangerous, only do this if you have no alternatives. + Instead of being gracefully cancelled, all jobs will be immediately sent to the completed + job table regardless of them being processed or not or part of running flows. You may end + up in an inconsistent state. +

+
+ {/if} {/if}