From 78d154cc7ff944b17d2eae8f40a7b7da7a689db3 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Tue, 28 Oct 2025 21:06:31 -0300 Subject: [PATCH] feat(bootstrap): add env check and improve config update logic Introduce environment existence check to prevent redundant bootstrap runs and ensure smoother startup. Refactor `update_bot_config` to use globally unique config keys and atomic updates for better data consistency. --- src/bootstrap/mod.rs | 27 ++++++++++++++++----------- src/main.rs | 39 ++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/mod.rs b/src/bootstrap/mod.rs index 216a099a..66d9b243 100644 --- a/src/bootstrap/mod.rs +++ b/src/bootstrap/mod.rs @@ -307,22 +307,27 @@ impl BootstrapManager { } fn update_bot_config(&self, bot_id: &uuid::Uuid, component: &str) -> Result<()> { + use diesel::sql_types::{Uuid as SqlUuid, Text}; let database_url = std::env::var("DATABASE_URL") .unwrap_or_else(|_| "postgres://gbuser:@localhost:5432/botserver".to_string()); let mut conn = diesel::pg::PgConnection::establish(&database_url)?; - let new_id: uuid::Uuid = uuid::Uuid::new_v4(); + // Ensure globally unique keys and update values atomically + let config_key = format!("{}_{}", bot_id, component); + let config_value = "true".to_string(); + let new_id = uuid::Uuid::new_v4(); - for (k, v) in vec![(component.to_string(), "true".to_string())] { - diesel::sql_query( - "INSERT INTO bot_configuration (id, bot_id, config_key, config_value, config_type) VALUES ($1, $2, $3, $4, 'string') ON CONFLICT (bot_id, config_key) DO UPDATE SET config_value = EXCLUDED.config_value, updated_at = NOW()", - ) - .bind::(new_id) - .bind::(bot_id) - .bind::(&k) - .bind::(&v) - .execute(&mut conn)?; - } + diesel::sql_query( + "INSERT INTO bot_configuration (id, bot_id, config_key, config_value, config_type) + VALUES ($1, $2, $3, $4, 'string') + ON CONFLICT (config_key) + DO UPDATE SET config_value = EXCLUDED.config_value, updated_at = NOW()" + ) + .bind::(new_id) + .bind::(bot_id) + .bind::(&config_key) + .bind::(&config_value) + .execute(&mut conn)?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 5e9ad0bf..e2bddc32 100644 --- a/src/main.rs +++ b/src/main.rs @@ -107,25 +107,38 @@ async fn main() -> std::io::Result<()> { }; let mut bootstrap = BootstrapManager::new(install_mode.clone(), tenant.clone()); - let cfg = match bootstrap.bootstrap() { - Ok(config) => { - info!("Bootstrap completed successfully"); - config + + // Prevent double bootstrap: skip if environment already initialized + let env_path = std::env::current_dir()?.join("botserver-stack").join(".env"); + let cfg = if env_path.exists() { + info!("Environment already initialized, skipping bootstrap"); + match diesel::Connection::establish( + &std::env::var("DATABASE_URL") + .unwrap_or_else(|_| "postgres://gbuser:@localhost:5432/botserver".to_string()), + ) { + Ok(mut conn) => AppConfig::from_database(&mut conn), + Err(_) => AppConfig::from_env(), } - Err(e) => { - log::error!("Bootstrap failed: {}", e); - match diesel::Connection::establish( - &std::env::var("DATABASE_URL") - .unwrap_or_else(|_| "postgres://gbuser:@localhost:5432/botserver".to_string()), - ) { - Ok(mut conn) => AppConfig::from_database(&mut conn), - Err(_) => { - AppConfig::from_env() + } else { + match bootstrap.bootstrap() { + Ok(config) => { + info!("Bootstrap completed successfully"); + config + } + Err(e) => { + log::error!("Bootstrap failed: {}", e); + match diesel::Connection::establish( + &std::env::var("DATABASE_URL") + .unwrap_or_else(|_| "postgres://gbuser:@localhost:5432/botserver".to_string()), + ) { + Ok(mut conn) => AppConfig::from_database(&mut conn), + Err(_) => AppConfig::from_env(), } } } }; + let _ = bootstrap.start_all(); if let Err(e) = bootstrap.upload_templates_to_minio(&cfg).await { log::warn!("Failed to upload templates to MinIO: {}", e);