chore: improve database pool connection options, tighter thresholds & limits

This commit is contained in:
2025-09-14 12:18:39 -05:00
parent 45de5be60d
commit 020a00254f

View File

@@ -12,6 +12,7 @@ use figment::{Figment, providers::Env};
use sqlx::postgres::PgPoolOptions; use sqlx::postgres::PgPoolOptions;
use std::process::ExitCode; use std::process::ExitCode;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use tracing::{error, info}; use tracing::{error, info};
/// Main application struct containing all necessary components /// Main application struct containing all necessary components
@@ -39,18 +40,30 @@ impl App {
.extract() .extract()
.expect("Failed to load config"); .expect("Failed to load config");
// Check if the database URL is via private networking
let is_private = config.database_url.contains("railway.internal");
let slow_threshold = if is_private {
Duration::from_millis(200)
} else {
Duration::from_millis(500)
};
// Create database connection pool // Create database connection pool
let db_pool = PgPoolOptions::new() let db_pool = PgPoolOptions::new()
.max_connections(10) .min_connections(0)
.max_connections(4)
.acquire_slow_threshold(slow_threshold)
.acquire_timeout(Duration::from_secs(4))
.idle_timeout(Duration::from_secs(60 * 2))
.max_lifetime(Duration::from_secs(60 * 30))
.connect(&config.database_url) .connect(&config.database_url)
.await .await
.expect("Failed to create database pool"); .expect("Failed to create database pool");
info!( info!(
port = config.port, is_private = is_private,
shutdown_timeout = format!("{:.2?}", config.shutdown_timeout), slow_threshold = format!("{:.2?}", slow_threshold),
banner_base_url = config.banner_base_url, "database pool established"
"configuration loaded"
); );
// Create BannerApi and AppState // Create BannerApi and AppState
@@ -77,19 +90,16 @@ impl App {
} }
/// Setup and register services based on enabled service list /// Setup and register services based on enabled service list
pub fn setup_services( pub fn setup_services(&mut self, services: &[ServiceName]) -> Result<(), anyhow::Error> {
&mut self,
enabled_services: &[ServiceName],
) -> Result<(), anyhow::Error> {
// Register enabled services with the manager // Register enabled services with the manager
if enabled_services.contains(&ServiceName::Web) { if services.contains(&ServiceName::Web) {
let web_service = let web_service =
Box::new(WebService::new(self.config.port, self.banner_state.clone())); Box::new(WebService::new(self.config.port, self.banner_state.clone()));
self.service_manager self.service_manager
.register_service(ServiceName::Web.as_str(), web_service); .register_service(ServiceName::Web.as_str(), web_service);
} }
if enabled_services.contains(&ServiceName::Scraper) { if services.contains(&ServiceName::Scraper) {
let scraper_service = Box::new(ScraperService::new( let scraper_service = Box::new(ScraperService::new(
self.db_pool.clone(), self.db_pool.clone(),
self.banner_api.clone(), self.banner_api.clone(),
@@ -98,12 +108,12 @@ impl App {
.register_service(ServiceName::Scraper.as_str(), scraper_service); .register_service(ServiceName::Scraper.as_str(), scraper_service);
} }
if enabled_services.contains(&ServiceName::Bot) { if services.contains(&ServiceName::Bot) {
// Bot service will be set up separately in run() method since it's async // Bot service will be set up separately in run() method since it's async
} }
// Check if any services are enabled // Check if any services are enabled
if !self.service_manager.has_services() && !enabled_services.contains(&ServiceName::Bot) { if !self.service_manager.has_services() && !services.contains(&ServiceName::Bot) {
error!("No services enabled. Cannot start application."); error!("No services enabled. Cannot start application.");
return Err(anyhow::anyhow!("No services enabled")); return Err(anyhow::anyhow!("No services enabled"));
} }