diff --git a/backend/windmill-api/src/db.rs b/backend/windmill-api/src/db.rs
index 4c3dd60696..76cfb7bd3b 100644
--- a/backend/windmill-api/src/db.rs
+++ b/backend/windmill-api/src/db.rs
@@ -15,7 +15,10 @@ use sqlx::{
use tokio::task::JoinHandle;
pub use windmill_common::db::DB;
-use windmill_common::{error::Error, utils::{generate_lock_id, GIT_VERSION}};
+use windmill_common::{
+ error::Error,
+ utils::{generate_lock_id, GIT_VERSION},
+};
#[allow(unused_imports)]
pub use windmill_api_auth::{ApiAuthed, OptJobAuthed};
@@ -255,8 +258,7 @@ pub async fn migrate(
if let Err(err) = sqlx::query!(
"DELETE FROM _sqlx_migrations WHERE
version=20250131115248 OR version=20250902085503 OR version=20250201145630 OR
- version=20250201145631 OR version=20250201145632 OR version=20251006143821 OR
- version=20260207000001 OR version=20260207000002 OR version=20260207000003 OR version=20260207000004"
+ version=20250201145631 OR version=20250201145632 OR version=20251006143821"
)
.execute(db)
.await
@@ -264,6 +266,31 @@ pub async fn migrate(
tracing::info!("Could not remove sqlx migrations: {err:#}");
}
+ // For migrations that were replaced (same version, new content), only delete if
+ // the stored checksum doesn't match the current file — i.e., it's a stale record
+ // from the old broken version. Once the new migration is applied, the checksum
+ // matches and the record is kept, avoiding expensive re-application on every start.
+ let migrator = sqlx::migrate!("../migrations");
+ let potentially_stale: &[i64] = &[
+ 20260207000001,
+ 20260207000002,
+ 20260207000003,
+ 20260207000004,
+ ];
+ for m in migrator.migrations.iter() {
+ if potentially_stale.contains(&m.version) {
+ if let Err(err) =
+ sqlx::query("DELETE FROM _sqlx_migrations WHERE version = $1 AND checksum != $2")
+ .bind(m.version)
+ .bind(&*m.checksum)
+ .execute(db)
+ .await
+ {
+ tracing::info!("Could not clean up stale migration {}: {err:#}", m.version);
+ }
+ }
+ }
+
tokio::select! {
_ = killpill_rx.recv() => {
tracing::info!("Killpill received, stopping migration");
@@ -309,12 +336,11 @@ pub async fn wait_for_migrations(
let mut attempts = 0;
loop {
- let is_applied: Result