use crank_config::DatabaseSettings; use crank_registry::{PostgresPoolConfig, PostgresRegistry, RegistryError}; use sqlx::{ PgPool, postgres::{PgConnectOptions, PgPoolOptions}, }; use std::time::Duration; use super::CliError; pub(super) async fn connect(config: &DatabaseSettings) -> Result { let options = connect_options(config)?; for attempt in 1..=10 { let result = PgPoolOptions::new() .max_connections(config.pool.max_connections) .min_connections(config.pool.min_connections) .acquire_timeout(Duration::from_millis(config.pool.acquire_timeout_ms)) .idle_timeout(Duration::from_millis(config.pool.idle_timeout_ms)) .max_lifetime(Duration::from_millis(config.pool.max_lifetime_ms)) .connect_with(options.clone()) .await; match result { Ok(pool) => return Ok(pool), Err(_) if attempt < 10 => tokio::time::sleep(Duration::from_secs(1)).await, Err(_) => break, } } Err(CliError::new( "storage_unavailable", "database.connect", "contact_operator", )) } pub(super) async fn connect_registry( config: &DatabaseSettings, ) -> Result { let options = connect_options(config)?; let pool_config = PostgresPoolConfig { max_connections: config.pool.max_connections, min_connections: config.pool.min_connections, acquire_timeout_ms: config.pool.acquire_timeout_ms, idle_timeout_ms: config.pool.idle_timeout_ms, max_lifetime_ms: config.pool.max_lifetime_ms, }; for attempt in 1..=10 { let result = PostgresRegistry::connect_with_options_and_pool_config(options.clone(), pool_config) .await; match result { Ok(registry) => return Ok(registry), Err(RegistryError::Storage(_)) if attempt < 10 => { tokio::time::sleep(Duration::from_secs(1)).await; } Err(error) => return Err(CliError::from_registry(error)), } } Err(CliError::new( "storage_unavailable", "database.connect", "contact_operator", )) } fn connect_options(config: &DatabaseSettings) -> Result { if let Some(url) = &config.url { url.expose_secret() .parse::() .map_err(|_| CliError::new("config_invalid", "database.source", "run_preflight")) } else { Ok(PgConnectOptions::new() .host(&config.host) .port(config.port) .database(&config.database) .username(&config.username) .password(config.password.expose_secret())) } }