Refactor database initialization to use a configuration struct for improved connection management
This commit is contained in:
parent
a7d3822f94
commit
6ac0d5e256
@ -34,7 +34,8 @@ var startCmd = &cobra.Command{
|
|||||||
|
|
||||||
// Database Setup
|
// Database Setup
|
||||||
dbDSN := viper.GetString("db-dsn")
|
dbDSN := viper.GetString("db-dsn")
|
||||||
database, err := db.NewDB(ctx, logger, dbDSN)
|
dbConfig := db.DefaultDBConfig(dbDSN)
|
||||||
|
database, err := db.NewDB(ctx, logger, dbConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed to initialize database", slog.Any("error", err))
|
logger.Error("failed to initialize database", slog.Any("error", err))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3" // SQLite driver
|
_ "github.com/mattn/go-sqlite3" // SQLite driver
|
||||||
)
|
)
|
||||||
@ -17,30 +18,56 @@ var ddl string
|
|||||||
|
|
||||||
// DBConfig holds database configuration.
|
// DBConfig holds database configuration.
|
||||||
type DBConfig struct {
|
type DBConfig struct {
|
||||||
DSN string // Data Source Name for SQLite
|
DSN string // Data Source Name for SQLite
|
||||||
|
MaxOpenConns int // Maximum number of open connections
|
||||||
|
MaxIdleConns int // Maximum number of idle connections
|
||||||
|
ConnMaxLifetime time.Duration // Maximum lifetime of connections
|
||||||
|
ConnMaxIdleTime time.Duration // Maximum idle time for connections
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultDBConfig returns a DBConfig with sensible defaults for SQLite.
|
||||||
|
func DefaultDBConfig(dsn string) *DBConfig {
|
||||||
|
return &DBConfig{
|
||||||
|
DSN: dsn,
|
||||||
|
MaxOpenConns: 25, // SQLite performs better with limited connections
|
||||||
|
MaxIdleConns: 10, // Keep some connections idle for reuse
|
||||||
|
ConnMaxLifetime: 30 * time.Minute, // Rotate connections every 30 minutes
|
||||||
|
ConnMaxIdleTime: 5 * time.Minute, // Close idle connections after 5 minutes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDB initializes and returns a new database connection pool and runs migrations.
|
// NewDB initializes and returns a new database connection pool and runs migrations.
|
||||||
func NewDB(ctx context.Context, logger *slog.Logger, dsn string) (*sql.DB, error) {
|
func NewDB(ctx context.Context, logger *slog.Logger, config *DBConfig) (*sql.DB, error) {
|
||||||
// Ensure the directory for the SQLite file exists
|
// Ensure the directory for the SQLite file exists
|
||||||
dbDir := filepath.Dir(dsn)
|
dbDir := filepath.Dir(config.DSN)
|
||||||
if err := os.MkdirAll(dbDir, 0755); err != nil {
|
if err := os.MkdirAll(dbDir, 0755); err != nil {
|
||||||
return nil, fmt.Errorf("failed to create database directory %s: %w", dbDir, err)
|
return nil, fmt.Errorf("failed to create database directory %s: %w", dbDir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := sql.Open("sqlite3", dsn+"?_foreign_keys=on") // Enable foreign key constraints
|
db, err := sql.Open("sqlite3", config.DSN+"?_foreign_keys=on") // Enable foreign key constraints
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to open database: %w", err)
|
return nil, fmt.Errorf("failed to open database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure connection pool
|
||||||
|
db.SetMaxOpenConns(config.MaxOpenConns)
|
||||||
|
db.SetMaxIdleConns(config.MaxIdleConns)
|
||||||
|
db.SetConnMaxLifetime(config.ConnMaxLifetime)
|
||||||
|
db.SetConnMaxIdleTime(config.ConnMaxIdleTime)
|
||||||
|
|
||||||
if err = db.PingContext(ctx); err != nil {
|
if err = db.PingContext(ctx); err != nil {
|
||||||
|
db.Close() // Clean up connection on failure
|
||||||
return nil, fmt.Errorf("failed to ping database: %w", err)
|
return nil, fmt.Errorf("failed to ping database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("database connection established", slog.String("dsn", dsn))
|
logger.Info("database connection established",
|
||||||
|
slog.String("dsn", config.DSN),
|
||||||
|
slog.Int("max_open_conns", config.MaxOpenConns),
|
||||||
|
slog.Int("max_idle_conns", config.MaxIdleConns))
|
||||||
|
|
||||||
// Execute schema.
|
// Execute schema.
|
||||||
if _, err := db.ExecContext(ctx, ddl); err != nil {
|
if _, err := db.ExecContext(ctx, ddl); err != nil {
|
||||||
|
db.Close() // Clean up connection on failure
|
||||||
return nil, fmt.Errorf("failed to execute DDL: %w", err)
|
return nil, fmt.Errorf("failed to execute DDL: %w", err)
|
||||||
}
|
}
|
||||||
logger.Info("database schema applied")
|
logger.Info("database schema applied")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user