[BE-DB-015] be-db: Optimize database connection pooling
This commit is contained in:
parent
e4412d88ee
commit
bf78bb2c42
3 changed files with 84 additions and 16 deletions
|
|
@ -3420,7 +3420,7 @@
|
|||
"description": "Configure proper connection pool settings for production",
|
||||
"owner": "backend",
|
||||
"estimated_hours": 3,
|
||||
"status": "todo",
|
||||
"status": "completed",
|
||||
"files_involved": [],
|
||||
"implementation_steps": [
|
||||
{
|
||||
|
|
@ -3441,7 +3441,9 @@
|
|||
"Unit tests",
|
||||
"Integration tests"
|
||||
],
|
||||
"notes": ""
|
||||
"notes": "",
|
||||
"completed_at": "2025-12-24T15:53:18.226129",
|
||||
"implementation_notes": "Optimized database connection pooling for production. Updated config.go to use environment variables (DB_MAX_OPEN_CONNS, DB_MAX_IDLE_CONNS, DB_MAX_LIFETIME, DB_MAX_IDLE_TIME) with optimized defaults: MaxOpenConns=50, MaxIdleConns=12, MaxLifetime=10m, MaxIdleTime=5m. Also updated pool.go to read from environment variables. Added helper functions getEnvAsInt and getEnvAsDuration for configuration parsing."
|
||||
},
|
||||
{
|
||||
"id": "BE-DB-016",
|
||||
|
|
|
|||
|
|
@ -466,10 +466,17 @@ func (l *filteredRedisLogger) Printf(ctx context.Context, format string, v ...in
|
|||
func initDatabaseWithRetry(databaseURL string, maxRetries int, retryInterval time.Duration, logger *zap.Logger) (*database.Database, error) {
|
||||
dbConfig := &database.Config{
|
||||
URL: databaseURL,
|
||||
MaxOpenConns: 25,
|
||||
MaxIdleConns: 10,
|
||||
MaxLifetime: 5 * time.Minute,
|
||||
MaxIdleTime: 1 * time.Minute,
|
||||
// BE-DB-015: Optimized connection pool settings for production
|
||||
// MaxOpenConns: Recommended formula: (2 * CPU cores) + effective_spindle_count
|
||||
// Default: 25 for small-medium apps, 50-100 for high-traffic apps
|
||||
MaxOpenConns: getEnvAsInt("DB_MAX_OPEN_CONNS", 50),
|
||||
// MaxIdleConns: Should be ~25% of MaxOpenConns to maintain warm connections
|
||||
MaxIdleConns: getEnvAsInt("DB_MAX_IDLE_CONNS", 12),
|
||||
// MaxLifetime: 5-15 minutes recommended to avoid connection timeouts
|
||||
// PostgreSQL default idle_in_transaction_session_timeout is 0 (unlimited)
|
||||
MaxLifetime: getEnvAsDuration("DB_MAX_LIFETIME", 10*time.Minute),
|
||||
// MaxIdleTime: 5-10 minutes to close idle connections and free resources
|
||||
MaxIdleTime: getEnvAsDuration("DB_MAX_IDLE_TIME", 5*time.Minute),
|
||||
MaxRetries: maxRetries,
|
||||
RetryInterval: retryInterval,
|
||||
}
|
||||
|
|
@ -543,6 +550,34 @@ func getEnv(key, defaultValue string) string {
|
|||
return defaultValue
|
||||
}
|
||||
|
||||
// getEnvAsInt retrieves an environment variable as an integer
|
||||
// BE-DB-015: Helper for connection pool configuration
|
||||
func getEnvAsInt(key string, defaultValue int) int {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
intValue, err := strconv.Atoi(strings.TrimSpace(value))
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
return intValue
|
||||
}
|
||||
|
||||
// getEnvAsDuration retrieves an environment variable as a time.Duration
|
||||
// BE-DB-015: Helper for connection pool configuration
|
||||
func getEnvAsDuration(key string, defaultValue time.Duration) time.Duration {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
duration, err := time.ParseDuration(strings.TrimSpace(value))
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
return duration
|
||||
}
|
||||
|
||||
// getEnvRequired récupère une variable d'environnement requise (retourne erreur si absente)
|
||||
func getEnvRequired(key string) (string, error) {
|
||||
value := os.Getenv(key)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package database
|
|||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"veza-backend-api/internal/metrics"
|
||||
|
|
@ -29,19 +31,48 @@ func NewDB(host string, port int, user, password, dbname string) (*gorm.DB, erro
|
|||
return nil, fmt.Errorf("failed to get underlying sql.DB: %w", err)
|
||||
}
|
||||
|
||||
// Configuration optimale du pool de connexions
|
||||
// MaxOpenConns: Nombre maximum de connexions ouvertes (25 recommandé pour PostgreSQL)
|
||||
sqlDB.SetMaxOpenConns(25)
|
||||
// BE-DB-015: Configuration optimale du pool de connexions pour la production
|
||||
// MaxOpenConns: Nombre maximum de connexions ouvertes
|
||||
// Recommandation: (2 * CPU cores) + effective_spindle_count
|
||||
// Default: 50 pour applications moyenne-grande charge, 25 pour petite charge
|
||||
maxOpenConns := 50
|
||||
if envMaxOpen := os.Getenv("DB_MAX_OPEN_CONNS"); envMaxOpen != "" {
|
||||
if parsed, err := strconv.Atoi(envMaxOpen); err == nil && parsed > 0 {
|
||||
maxOpenConns = parsed
|
||||
}
|
||||
}
|
||||
sqlDB.SetMaxOpenConns(maxOpenConns)
|
||||
|
||||
// MaxIdleConns: Nombre maximum de connexions inactives (5 recommandé)
|
||||
sqlDB.SetMaxIdleConns(5)
|
||||
// MaxIdleConns: Nombre maximum de connexions inactives
|
||||
// Recommandation: ~25% de MaxOpenConns pour maintenir des connexions chaudes
|
||||
maxIdleConns := 12
|
||||
if envMaxIdle := os.Getenv("DB_MAX_IDLE_CONNS"); envMaxIdle != "" {
|
||||
if parsed, err := strconv.Atoi(envMaxIdle); err == nil && parsed > 0 {
|
||||
maxIdleConns = parsed
|
||||
}
|
||||
}
|
||||
sqlDB.SetMaxIdleConns(maxIdleConns)
|
||||
|
||||
// ConnMaxLifetime: Durée maximale de vie d'une connexion (5 minutes)
|
||||
// Cela permet de recycler les connexions et éviter les problèmes de timeout
|
||||
sqlDB.SetConnMaxLifetime(5 * time.Minute)
|
||||
// ConnMaxLifetime: Durée maximale de vie d'une connexion
|
||||
// Recommandation: 5-15 minutes pour éviter les timeouts de connexion
|
||||
// PostgreSQL idle_in_transaction_session_timeout peut être configuré côté serveur
|
||||
maxLifetime := 10 * time.Minute
|
||||
if envMaxLifetime := os.Getenv("DB_MAX_LIFETIME"); envMaxLifetime != "" {
|
||||
if parsed, err := time.ParseDuration(envMaxLifetime); err == nil && parsed > 0 {
|
||||
maxLifetime = parsed
|
||||
}
|
||||
}
|
||||
sqlDB.SetConnMaxLifetime(maxLifetime)
|
||||
|
||||
// ConnMaxIdleTime: Durée maximale d'inactivité d'une connexion avant fermeture (1 minute)
|
||||
sqlDB.SetConnMaxIdleTime(1 * time.Minute)
|
||||
// ConnMaxIdleTime: Durée maximale d'inactivité d'une connexion avant fermeture
|
||||
// Recommandation: 5-10 minutes pour libérer les ressources inutilisées
|
||||
maxIdleTime := 5 * time.Minute
|
||||
if envMaxIdleTime := os.Getenv("DB_MAX_IDLE_TIME"); envMaxIdleTime != "" {
|
||||
if parsed, err := time.ParseDuration(envMaxIdleTime); err == nil && parsed > 0 {
|
||||
maxIdleTime = parsed
|
||||
}
|
||||
}
|
||||
sqlDB.SetConnMaxIdleTime(maxIdleTime)
|
||||
|
||||
// Test de la connexion
|
||||
if err := sqlDB.Ping(); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue