From d7a79d960b56170e59e10a2b6b047ddc2564f931 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Wed, 25 Mar 2026 17:38:28 +0100 Subject: [PATCH] refactor: extract drop_custom_instance_database into windmill-common Co-Authored-By: Claude Opus 4.5 --- backend/windmill-api-settings/src/lib.rs | 22 +---------- .../src/workspaces_extra.rs | 10 +---- backend/windmill-common/src/lib.rs | 38 +++++++++++++++++++ 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/backend/windmill-api-settings/src/lib.rs b/backend/windmill-api-settings/src/lib.rs index df34c01081..f3283e5235 100644 --- a/backend/windmill-api-settings/src/lib.rs +++ b/backend/windmill-api-settings/src/lib.rs @@ -1042,27 +1042,7 @@ async fn drop_custom_instance_pg_database( ))); } - // Terminate all connections to the database before dropping - sqlx::query(&format!( - "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{dbname}' AND pid <> pg_backend_pid()" - )) - .execute(&db) - .await?; - - sqlx::query(&format!("DROP DATABASE \"{dbname}\"")) - .execute(&db) - .await - .map_err(|e| { - error::Error::ExecutionErr(format!("Failed to drop database '{}': {}", dbname, e)) - })?; - - // Remove from global_settings - sqlx::query!( - r#"UPDATE global_settings SET value = value #- ARRAY['databases', $1] WHERE name = 'custom_instance_pg_databases'"#, - dbname - ) - .execute(&db) - .await?; + windmill_common::drop_custom_instance_database(&db, dbname).await; Ok(format!("Database '{}' dropped successfully", dbname)) } diff --git a/backend/windmill-api-workspaces/src/workspaces_extra.rs b/backend/windmill-api-workspaces/src/workspaces_extra.rs index df9f42e4e1..629a8fc42e 100644 --- a/backend/windmill-api-workspaces/src/workspaces_extra.rs +++ b/backend/windmill-api-workspaces/src/workspaces_extra.rs @@ -899,15 +899,7 @@ async fn drop_forked_datatable_databases( if dt.database.resource_type == windmill_common::workspaces::DataTableCatalogResourceType::Instance { - match sqlx::query(&format!("DROP DATABASE IF EXISTS \"{}\"", db_to_drop)) - .execute(db) - .await - { - Ok(_) => tracing::info!("Dropped instance database '{}'", db_to_drop), - Err(e) => { - tracing::error!("Failed to drop instance database '{}': {}", db_to_drop, e) - } - } + windmill_common::drop_custom_instance_database(db, db_to_drop).await; } else if let Some(original_resource) = forked_from.get("original_resource") { let pg = match serde_json::from_value::(original_resource.clone()) { Ok(pg) => pg, diff --git a/backend/windmill-common/src/lib.rs b/backend/windmill-common/src/lib.rs index 18fadbfbc7..733f7622b3 100644 --- a/backend/windmill-common/src/lib.rs +++ b/backend/windmill-common/src/lib.rs @@ -552,6 +552,44 @@ impl PgDatabase { } } +/// Drop a custom instance database: terminate connections, DROP DATABASE, remove from global_settings. +/// Non-fatal variant that logs errors instead of returning them. +pub async fn drop_custom_instance_database(db: &DB, dbname: &str) { + // Terminate active connections + if let Err(e) = sqlx::query(&format!( + "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{}' AND pid <> pg_backend_pid()", + dbname.replace('\'', "''") + )) + .execute(db) + .await + { + tracing::warn!("Failed to terminate connections to '{}': {}", dbname, e); + } + + // Drop the database + match sqlx::query(&format!("DROP DATABASE IF EXISTS \"{}\"", dbname)) + .execute(db) + .await + { + Ok(_) => tracing::info!("Dropped instance database '{}'", dbname), + Err(e) => { + tracing::error!("Failed to drop instance database '{}': {}", dbname, e); + return; + } + } + + // Remove from global_settings + if let Err(e) = sqlx::query!( + r#"UPDATE global_settings SET value = value #- ARRAY['databases', $1] WHERE name = 'custom_instance_pg_databases'"#, + dbname + ) + .execute(db) + .await + { + tracing::error!("Failed to remove '{}' from global_settings: {}", dbname, e); + } +} + #[derive(Clone)] pub enum DatabaseUrl { #[cfg(all(feature = "enterprise", feature = "private"))]