/
database.go
124 lines (107 loc) · 2.95 KB
/
database.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/iver-wharf/wharf-core/pkg/gormutil"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var errUnsupportedDBDriver = errors.New("unsupported database driver")
func openDatabase(config DBConfig) (*gorm.DB, error) {
log.Info().WithString("driver", string(config.Driver)).Message("Connecting to database.")
switch config.Driver {
case DBDriverPostgres:
return openDatabasePostgres(config)
case DBDriverSqlite:
return openDatabaseSqlite(config)
default:
return nil, errUnsupportedDBDriver
}
}
func openDatabaseSqlite(config DBConfig) (*gorm.DB, error) {
if err := os.MkdirAll(filepath.Dir(config.Path), os.ModePerm); err != nil {
return nil, fmt.Errorf("create directories for sqlite file: %w", err)
}
var gormConfig = getGormConfig(config)
return gorm.Open(sqlite.Open(config.Path), &gormConfig)
}
func openDatabasePostgres(config DBConfig) (*gorm.DB, error) {
const retryDelay = 2 * time.Second
const maxAttempts = 3
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=postgres sslmode=disable",
config.Host,
config.Port,
config.Username,
config.Password)
var gormConfig = getGormConfig(config)
var db *gorm.DB
var err error
for attempt := 1; attempt <= maxAttempts; attempt++ {
db, err = gorm.Open(postgres.Open(psqlInfo), &gormConfig)
if err == nil {
break
}
if attempt < maxAttempts {
log.Warn().
WithError(err).
WithInt("attempt", attempt).
WithInt("maxAttempts", maxAttempts).
WithDuration("retryAfter", retryDelay).
Message("Failed attempt to reach database.")
time.Sleep(retryDelay)
} else {
log.Warn().
WithError(err).
WithInt("maxAttempts", maxAttempts).
Message("Failed all attempts to reach database.")
}
}
if err != nil {
return db, err
}
db.Exec(fmt.Sprintf("CREATE DATABASE %s;", config.Name))
psqlInfo = fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
config.Host,
config.Port,
config.Username,
config.Password,
config.Name)
db, err = gorm.Open(postgres.Open(psqlInfo), &gormConfig)
if err != nil {
return db, err
}
sqlDB, err := db.DB()
if err != nil {
return db, err
}
log.Debug().
WithInt("maxIdleConns", config.MaxIdleConns).
WithInt("maxOpenConns", config.MaxOpenConns).
WithDuration("maxConnLifetime", config.MaxConnLifetime).
Message("Setting database config.")
sqlDB.SetMaxIdleConns(config.MaxIdleConns)
sqlDB.SetMaxOpenConns(config.MaxOpenConns)
sqlDB.SetConnMaxLifetime(config.MaxConnLifetime)
err = sqlDB.Ping()
return db, err
}
func getGormConfig(config DBConfig) gorm.Config {
return gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
Logger: getLogger(config),
}
}
func getLogger(config DBConfig) logger.Interface {
if config.Log {
return gormutil.DefaultLogger
}
return logger.Default.LogMode(logger.Silent)
}