REFACTOR: Create Single Connection For App Lifetime
Build, Push and Deploy CMS / build-push-deploy (push) Successful in 2m6s

This commit is contained in:
FahdShalhoub
2026-08-16 23:05:15 +03:00
parent 785154cec6
commit 8bf0eae425
2 changed files with 25 additions and 30 deletions
+21 -28
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
"log"
"thamanyah/cms/v2/internal/db" "thamanyah/cms/v2/internal/db"
"time" "time"
) )
@@ -31,17 +32,21 @@ type DBClient interface {
} }
type DBConcrete struct { type DBConcrete struct {
ConnectionString string SQLDB *sql.DB
}
func CreateConcreteDbClient(connectionString string) DBConcrete {
sqlDB, err := sql.Open("postgres", connectionString)
if err != nil {
panic(fmt.Errorf("db: cannot open connection: %w", err))
}
return DBConcrete{
SQLDB: sqlDB,
}
} }
func (svc DBConcrete) CreateVideo(ctx context.Context, v Video) (Video, error) { func (svc DBConcrete) CreateVideo(ctx context.Context, v Video) (Video, error) {
sqlDB, err := sql.Open("postgres", svc.ConnectionString) tx, err := svc.SQLDB.BeginTx(ctx, nil)
if err != nil {
return Video{}, err
}
defer sqlDB.Close()
tx, err := sqlDB.BeginTx(ctx, nil)
if err != nil { if err != nil {
return Video{}, err return Video{}, err
} }
@@ -75,13 +80,7 @@ func (svc DBConcrete) CreateVideo(ctx context.Context, v Video) (Video, error) {
} }
func (svc DBConcrete) ListCategories(ctx context.Context) ([]string, error) { func (svc DBConcrete) ListCategories(ctx context.Context) ([]string, error) {
sqlDB, err := sql.Open("postgres", svc.ConnectionString) rows, err := svc.SQLDB.QueryContext(ctx, `SELECT name FROM categories ORDER BY name`)
if err != nil {
return nil, err
}
defer sqlDB.Close()
rows, err := sqlDB.QueryContext(ctx, `SELECT name FROM categories ORDER BY name`)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -99,26 +98,20 @@ func (svc DBConcrete) ListCategories(ctx context.Context) ([]string, error) {
} }
func (svc DBConcrete) Migrate() { func (svc DBConcrete) Migrate() {
sqlDB, err := sql.Open("postgres", svc.ConnectionString) if err := db.Migrate(svc.SQLDB); err != nil {
if err != nil {
panic(fmt.Errorf("failed to open db connection: %w", err))
}
if err := db.Migrate(sqlDB); err != nil {
panic(err) panic(err)
} }
sqlDB.Close()
} }
// AssertSuccessfulConnection verifies the database is reachable, mirroring func (svc DBConcrete) CloseConnection() {
// S3Concrete's boot-time check — panics rather than let the service come up broken. err := svc.SQLDB.Close()
func (svc DBConcrete) AssertSuccessfulConnection(ctx context.Context) {
sqlDB, err := sql.Open("postgres", svc.ConnectionString)
if err != nil { if err != nil {
panic(fmt.Errorf("db: cannot open connection: %w", err)) log.Fatalf("Error Closing DB Connection: %s", err)
} }
defer sqlDB.Close() }
if err := sqlDB.PingContext(ctx); err != nil { func (svc DBConcrete) AssertSuccessfulConnection(ctx context.Context) {
if err := svc.SQLDB.PingContext(ctx); err != nil {
panic(fmt.Errorf("db: cannot connect: %w", err)) panic(fmt.Errorf("db: cannot connect: %w", err))
} }
} }
+4 -2
View File
@@ -24,7 +24,8 @@ func main() {
} }
func runMigrate() { func runMigrate() {
concreteDBClient := &services.DBConcrete{ConnectionString: requireDBConnectionString()} concreteDBClient := services.CreateConcreteDbClient(requireDBConnectionString())
defer concreteDBClient.CloseConnection()
concreteDBClient.Migrate() concreteDBClient.Migrate()
log.Println("migrations applied successfully") log.Println("migrations applied successfully")
} }
@@ -70,7 +71,8 @@ func runServer() {
OutputBucket: mediaConvertOutputBucket, OutputBucket: mediaConvertOutputBucket,
} }
concreteDBClient := &services.DBConcrete{ConnectionString: requireDBConnectionString()} concreteDBClient := services.CreateConcreteDbClient(requireDBConnectionString())
defer concreteDBClient.CloseConnection()
concreteDBClient.AssertSuccessfulConnection(context.Background()) concreteDBClient.AssertSuccessfulConnection(context.Background())
services.DB = concreteDBClient services.DB = concreteDBClient