From 8bf0eae4254f53bc3ea98816d376b169706e6926 Mon Sep 17 00:00:00 2001 From: FahdShalhoub Date: Sun, 16 Aug 2026 23:05:15 +0300 Subject: [PATCH] REFACTOR: Create Single Connection For App Lifetime --- cms/internal/services/db.go | 49 ++++++++++++++++--------------------- cms/main.go | 6 +++-- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/cms/internal/services/db.go b/cms/internal/services/db.go index a18d596..86894c7 100644 --- a/cms/internal/services/db.go +++ b/cms/internal/services/db.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "fmt" + "log" "thamanyah/cms/v2/internal/db" "time" ) @@ -31,17 +32,21 @@ type DBClient interface { } 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) { - sqlDB, err := sql.Open("postgres", svc.ConnectionString) - if err != nil { - return Video{}, err - } - defer sqlDB.Close() - - tx, err := sqlDB.BeginTx(ctx, nil) + tx, err := svc.SQLDB.BeginTx(ctx, nil) if err != nil { 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) { - sqlDB, err := sql.Open("postgres", svc.ConnectionString) - if err != nil { - return nil, err - } - defer sqlDB.Close() - - rows, err := sqlDB.QueryContext(ctx, `SELECT name FROM categories ORDER BY name`) + rows, err := svc.SQLDB.QueryContext(ctx, `SELECT name FROM categories ORDER BY name`) if err != nil { return nil, err } @@ -99,26 +98,20 @@ func (svc DBConcrete) ListCategories(ctx context.Context) ([]string, error) { } func (svc DBConcrete) Migrate() { - sqlDB, err := sql.Open("postgres", svc.ConnectionString) - if err != nil { - panic(fmt.Errorf("failed to open db connection: %w", err)) - } - if err := db.Migrate(sqlDB); err != nil { + if err := db.Migrate(svc.SQLDB); err != nil { panic(err) } - sqlDB.Close() } -// AssertSuccessfulConnection verifies the database is reachable, mirroring -// S3Concrete's boot-time check — panics rather than let the service come up broken. -func (svc DBConcrete) AssertSuccessfulConnection(ctx context.Context) { - sqlDB, err := sql.Open("postgres", svc.ConnectionString) +func (svc DBConcrete) CloseConnection() { + err := svc.SQLDB.Close() 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)) } } diff --git a/cms/main.go b/cms/main.go index f383880..95764db 100644 --- a/cms/main.go +++ b/cms/main.go @@ -24,7 +24,8 @@ func main() { } func runMigrate() { - concreteDBClient := &services.DBConcrete{ConnectionString: requireDBConnectionString()} + concreteDBClient := services.CreateConcreteDbClient(requireDBConnectionString()) + defer concreteDBClient.CloseConnection() concreteDBClient.Migrate() log.Println("migrations applied successfully") } @@ -70,7 +71,8 @@ func runServer() { OutputBucket: mediaConvertOutputBucket, } - concreteDBClient := &services.DBConcrete{ConnectionString: requireDBConnectionString()} + concreteDBClient := services.CreateConcreteDbClient(requireDBConnectionString()) + defer concreteDBClient.CloseConnection() concreteDBClient.AssertSuccessfulConnection(context.Background()) services.DB = concreteDBClient