mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-18 08:03:11 +00:00
feat: restart perpetual runs on the version a deploy makes runnable (#11200)
* feat: opt-in move of perpetual runs to a newly deployed script version Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep the perpetual-run opt-in across relocks and check the new version's tag Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test: pin the tag check on a perpetual version switch Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: count perpetual runs past the first queue page in the deploy prompt Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: restart perpetual runs on the version a deploy makes runnable Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: claim a perpetual run and queue its replacement in one transaction Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: honour a cancel that lands after the worker last read its queue row Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: leave the lost-cancel fix to its own PR and match the scale down to 0 wording Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: run a preprocessor the deployed version adds over the arguments carried over Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * style: shorten the wording of the modal's argument warning Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: never preprocess a restarted perpetual run, as every other restart does Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: preprocess for a replacement whose run had not been through one Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: push a perpetual replacement without the deployed debounce settings Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: name the runs the deploy button restarts Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * perf: skip the perpetual restart lookups on a deploy that is not perpetual Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: move perpetual runs before anything that can fail after the deploy commits Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: report cancellation on the queue listing so the deploy prompt can skip it Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: pass the tag workspace to the availability check after the merge Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * style: say which arguments are defined differently and which values are kept Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: resolve a dynamic tag before checking it for a restarted run Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test: pin that a deployed dynamic tag is checked as it resolves Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bda00c6cad
commit
cf5c49c3dc
@@ -551,6 +551,7 @@ async fn create_snapshot_script(
|
||||
let mut handle_deployment_metadata = None;
|
||||
let mut moved_native_triggers = Vec::new();
|
||||
let mut deployed_path = None;
|
||||
let mut deployed_perpetual = false;
|
||||
while let Some(field) = multipart.next_field().await.unwrap() {
|
||||
let name = field.name().unwrap().to_string();
|
||||
let data = field.bytes().await.unwrap();
|
||||
@@ -559,6 +560,7 @@ async fn create_snapshot_script(
|
||||
let is_tar = ns.codebase.as_ref().is_some_and(|x| x.ends_with(".tar"));
|
||||
let use_esm = ns.codebase.as_ref().is_some_and(|x| x.contains(".esm"));
|
||||
deployed_path = Some(ns.path.clone());
|
||||
deployed_perpetual = ns.restart_unless_cancelled == Some(true);
|
||||
let (new_hash, ntx, hdm, moved) = create_script_internal(
|
||||
ns,
|
||||
w_id.clone(),
|
||||
@@ -616,6 +618,19 @@ async fn create_snapshot_script(
|
||||
}
|
||||
reregister_moved_native_triggers(&db, &authed, &w_id, moved_native_triggers);
|
||||
if let Some(hdm) = handle_deployment_metadata {
|
||||
let runnable_now = matches!(hdm, PostCommitDeploy::Full { .. });
|
||||
if let Some(script_path) = deployed_path
|
||||
.as_deref()
|
||||
.filter(|_| runnable_now && deployed_perpetual)
|
||||
{
|
||||
windmill_queue::restart_perpetual_runs_on_new_version(
|
||||
&db,
|
||||
&w_id,
|
||||
script_path,
|
||||
&authed.username,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
hdm.handle(&db).await?;
|
||||
}
|
||||
return Ok((StatusCode::CREATED, format!("{}", script_hash.unwrap())));
|
||||
@@ -734,6 +749,9 @@ async fn deploy_script(
|
||||
return Err(Error::PermissionDenied(msg));
|
||||
}
|
||||
let script_path = ns.path.clone();
|
||||
// Only a perpetual deploy can have runs to move, so every other one skips the lookups that
|
||||
// would find that out.
|
||||
let perpetual = ns.restart_unless_cancelled == Some(true);
|
||||
let email = authed.email.clone();
|
||||
let username = authed.username.clone();
|
||||
let authed_for_triggers = authed.clone();
|
||||
@@ -757,6 +775,19 @@ async fn deploy_script(
|
||||
// they don't run against a version whose lock does not exist yet — and
|
||||
// don't run twice.
|
||||
let ready_to_test = matches!(hdm, PostCommitDeploy::Full { .. });
|
||||
// The version is runnable, so the perpetual runs of earlier ones move to it here, before
|
||||
// anything that can fail this deploy after its commit: a version nothing moved to would
|
||||
// leave those runs on the old code with nothing left to notice. A deploy that needed lock
|
||||
// generation hands this to its dependency job instead.
|
||||
if ready_to_test && perpetual {
|
||||
windmill_queue::restart_perpetual_runs_on_new_version(
|
||||
&db,
|
||||
&w_id,
|
||||
&script_path,
|
||||
&username,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
hdm.handle(&db).await?;
|
||||
let db2 = db.clone();
|
||||
if ready_to_test {
|
||||
@@ -2864,6 +2895,12 @@ async fn create_script_internal<'c>(
|
||||
if let Some(dm) = ns.deployment_message {
|
||||
args.insert("deployment_message".to_string(), to_raw_value(&dm));
|
||||
}
|
||||
// The version becomes runnable when this job writes its lock, which is where the
|
||||
// perpetual runs of earlier versions can move to it. Only a deploy someone made carries
|
||||
// this, so a relock triggered by an imported script changing leaves those runs alone.
|
||||
if ns.restart_unless_cancelled.is_some_and(|x| x) {
|
||||
args.insert("restart_perpetual_runs".to_string(), to_raw_value(&true));
|
||||
}
|
||||
if let Some(ref p_path) = p_path_opt {
|
||||
args.insert("parent_path".to_string(), to_raw_value(&p_path));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user