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.
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-10-28 21:06:31 -03:00
parent 44c745ef57
commit 78d154cc7f
2 changed files with 42 additions and 24 deletions

View file

@ -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::<diesel::sql_types::Uuid, _>(new_id)
.bind::<diesel::sql_types::Uuid, _>(bot_id)
.bind::<diesel::sql_types::Text, _>(&k)
.bind::<diesel::sql_types::Text, _>(&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::<SqlUuid, _>(new_id)
.bind::<SqlUuid, _>(bot_id)
.bind::<Text, _>(&config_key)
.bind::<Text, _>(&config_value)
.execute(&mut conn)?;
Ok(())
}

View file

@ -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);