Extract ~200 lines of duplicate database connection code from api/ntpdb/ and monitor/ntpdb/ into common/database/ package. Creates foundation for database consolidation while maintaining zero breaking changes. Files added: - config.go: Unified configuration with package-specific defaults - connector.go: Dynamic connector pattern from Boostport - pool.go: Configurable connection pool management - metrics.go: Optional Prometheus metrics integration - interfaces.go: Shared database interfaces for consistent patterns Key features: - Configuration-driven approach (API: 25/10 connections + metrics, Monitor: 10/5 connections, no metrics) - Optional Prometheus metrics when registerer provided - Backward compatibility via convenience functions - Flexible config file loading (explicit paths + search-based) Dependencies: Added mysql driver and yaml parsing for database configuration.
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"os"
|
|
|
|
"go.ntppool.org/common/logger"
|
|
)
|
|
|
|
// OpenDB opens a database connection with the specified configuration options
|
|
func OpenDB(ctx context.Context, options ConfigOptions) (*sql.DB, error) {
|
|
log := logger.Setup()
|
|
|
|
configFile, err := findConfigFile(options.ConfigFiles)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dbconn := sql.OpenDB(Driver{
|
|
CreateConnectorFunc: createConnector(configFile),
|
|
})
|
|
|
|
// Set connection pool parameters
|
|
dbconn.SetConnMaxLifetime(options.ConnMaxLifetime)
|
|
dbconn.SetMaxOpenConns(options.MaxOpenConns)
|
|
dbconn.SetMaxIdleConns(options.MaxIdleConns)
|
|
|
|
err = dbconn.Ping()
|
|
if err != nil {
|
|
log.Error("could not connect to database", "err", err)
|
|
return nil, err
|
|
}
|
|
|
|
// Start optional connection pool monitoring
|
|
if options.EnablePoolMonitoring && options.PrometheusRegisterer != nil {
|
|
go monitorConnectionPool(ctx, dbconn, options.PrometheusRegisterer)
|
|
}
|
|
|
|
return dbconn, nil
|
|
}
|
|
|
|
// OpenDBWithConfigFile opens a database connection using an explicit config file path
|
|
// This is a convenience function for API package compatibility
|
|
func OpenDBWithConfigFile(ctx context.Context, configFile string) (*sql.DB, error) {
|
|
options := DefaultConfigOptions()
|
|
options.ConfigFiles = []string{configFile}
|
|
return OpenDB(ctx, options)
|
|
}
|
|
|
|
// OpenDBMonitor opens a database connection with monitor-specific defaults
|
|
// This is a convenience function for Monitor package compatibility
|
|
func OpenDBMonitor() (*sql.DB, error) {
|
|
options := MonitorConfigOptions()
|
|
return OpenDB(context.Background(), options)
|
|
}
|
|
|
|
// findConfigFile searches for the first existing config file from the list
|
|
func findConfigFile(configFiles []string) (string, error) {
|
|
var firstErr error
|
|
|
|
for _, configFile := range configFiles {
|
|
if configFile == "" {
|
|
continue
|
|
}
|
|
if _, err := os.Stat(configFile); err == nil {
|
|
return configFile, nil
|
|
} else if firstErr == nil {
|
|
firstErr = err
|
|
}
|
|
}
|
|
|
|
if firstErr != nil {
|
|
return "", fmt.Errorf("no config file found: %w", firstErr)
|
|
}
|
|
return "", fmt.Errorf("no valid config files provided")
|
|
}
|