100 lines
2.8 KiB
Go
100 lines
2.8 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
|
|
"base/config"
|
|
"base/pkg/metrics"
|
|
)
|
|
|
|
// NewRWDatabaseConnection creates a new database connection
|
|
func NewRWDatabaseConnection(cfg *config.AppConfig, logger zerolog.Logger, metric *metrics.Metrics) (*gorm.DB, error) {
|
|
start := time.Now()
|
|
|
|
lg := logger.
|
|
With().
|
|
Str("module", "database").
|
|
Int("maxOpenConnection", cfg.Database.MaxOpenConns).
|
|
Int("maxIdleConnection", cfg.Database.MaxIdleConns).
|
|
Logger()
|
|
|
|
gormConfig := &gorm.Config{Logger: NewGormLogger(logger, time.Second*5)}
|
|
|
|
wrDB, sqlDB, err := wr(cfg, gormConfig)
|
|
if err != nil {
|
|
fmt.Println("[DATABASE CONNECTION ERROR]Failed to connect to database", err.Error())
|
|
metric.RecordDatabaseQuery("ConnectWR", "database", time.Since(start), err)
|
|
|
|
lg.Error().
|
|
Err(err).
|
|
Msg("failed to connect to database")
|
|
|
|
return nil, err
|
|
}
|
|
|
|
metric.RecordDatabaseQuery("ConnectWR", "database", time.Since(start), nil)
|
|
|
|
// Start monitoring connection pool metrics
|
|
go monitorConnectionPool(sqlDB, metric, logger)
|
|
|
|
duration := time.Since(start)
|
|
metric.RecordDatabaseQuery("Connect", "database", duration, nil)
|
|
|
|
lg.Info().Msg("Database connection established")
|
|
|
|
return wrDB, nil
|
|
}
|
|
|
|
func wr(config *config.AppConfig, gormConfig *gorm.Config) (*gorm.DB, *sql.DB, error) {
|
|
// PostgreSQL DSN format: postgres://user:password@host:port/dbname?sslmode=disable
|
|
dsn := fmt.Sprintf(
|
|
"host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=UTC",
|
|
config.PgDatabaseConfig.Host,
|
|
config.PgDatabaseConfig.User,
|
|
config.PgDatabaseConfig.Password,
|
|
config.PgDatabaseConfig.Name,
|
|
config.PgDatabaseConfig.Port,
|
|
config.PgDatabaseConfig.SSLMode,
|
|
)
|
|
|
|
db, err := gorm.Open(postgres.Open(dsn), gormConfig)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Get the underlying sql.DB
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
sqlDB.SetMaxIdleConns(int(config.PgDatabaseConfig.PoolConfig.MinConn))
|
|
sqlDB.SetMaxOpenConns(int(config.PgDatabaseConfig.PoolConfig.MaxConn))
|
|
|
|
// Parse and set connection timeouts from config
|
|
// TODO: this is not type safe
|
|
if config.PgDatabaseConfig.PoolConfig.MaxConnIdleTime.String() != "" {
|
|
if idleTime, parseDurationErr := time.ParseDuration(config.PgDatabaseConfig.PoolConfig.MaxConnIdleTime.String()); parseDurationErr == nil {
|
|
sqlDB.SetConnMaxIdleTime(idleTime)
|
|
} else {
|
|
sqlDB.SetConnMaxIdleTime(5 * time.Minute)
|
|
}
|
|
}
|
|
|
|
if config.PgDatabaseConfig.PoolConfig.MaxConnLifetime.String() != "" {
|
|
if lifetime, parseDurationErr := time.ParseDuration(config.PgDatabaseConfig.PoolConfig.MaxConnLifetime.String()); parseDurationErr == nil {
|
|
sqlDB.SetConnMaxLifetime(lifetime)
|
|
} else {
|
|
sqlDB.SetConnMaxLifetime(30 * time.Minute)
|
|
}
|
|
}
|
|
|
|
return db, sqlDB, nil
|
|
}
|