mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-13 05:45:41 +08:00
add utility package for establishing db driver connections (#51)
This commit is contained in:
38
driver/driver.go
Normal file
38
driver/driver.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Package driver provides utilities for creating reliablie connections to
|
||||
// external services like redis and sql databases.
|
||||
package driver
|
||||
|
||||
import "github.com/go-kit/kit/log"
|
||||
|
||||
const defaultAttempts = 20
|
||||
|
||||
// ConnOption is a driver connection option.
|
||||
type ConnOption func(c *config)
|
||||
|
||||
type config struct {
|
||||
logger log.Logger
|
||||
maxAttempts int
|
||||
redisPassword string
|
||||
}
|
||||
|
||||
// Logger adds a logger to the connection config.
|
||||
func Logger(logger log.Logger) ConnOption {
|
||||
return func(c *config) {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// WithAttemtps t allows overriding the default 20 attempts for creating
|
||||
// a driver connection.
|
||||
func WithAttemtps(n int) ConnOption {
|
||||
return func(c *config) {
|
||||
c.maxAttempts = n
|
||||
}
|
||||
}
|
||||
|
||||
// WithPassword adds an AUTH check when creating a redis pool.
|
||||
func WithPassword(password string) ConnOption {
|
||||
return func(c *config) {
|
||||
c.redisPassword = password
|
||||
}
|
||||
}
|
||||
68
driver/redis.go
Normal file
68
driver/redis.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
// NewRedisPool creates a redis pool with a backoff timer. By default,
|
||||
// 20 attempts will be made, with a 1 second increasing interval.
|
||||
func NewRedisPool(conn string, opts ...ConnOption) (*redis.Pool, error) {
|
||||
conf := &config{
|
||||
logger: log.NewNopLogger(),
|
||||
maxAttempts: defaultAttempts,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(conf)
|
||||
}
|
||||
|
||||
pool := &redis.Pool{
|
||||
MaxIdle: 3,
|
||||
IdleTimeout: 240 * time.Second,
|
||||
Dial: func() (redis.Conn, error) {
|
||||
c, err := redis.Dial("tcp", conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if conf.redisPassword != "" {
|
||||
if _, err := c.Do("AUTH", conf.redisPassword); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
},
|
||||
TestOnBorrow: func(c redis.Conn, t time.Time) error {
|
||||
if time.Since(t) < time.Minute {
|
||||
return nil
|
||||
}
|
||||
_, err := c.Do("PING")
|
||||
return err
|
||||
},
|
||||
}
|
||||
if err := checkRedisConn(pool, conf.maxAttempts, conf.logger); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func checkRedisConn(pool *redis.Pool, maxAttempts int, logger log.Logger) error {
|
||||
conn := pool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
var dbError error
|
||||
for attempts := 1; attempts <= maxAttempts; attempts++ {
|
||||
_, dbError = conn.Do("PING")
|
||||
if dbError == nil {
|
||||
break
|
||||
}
|
||||
sleep := time.Duration(attempts)
|
||||
logger.Log("msg", fmt.Sprintf(
|
||||
"could not connect to redis: %v, sleeping %v", dbError, sleep))
|
||||
time.Sleep(sleep * time.Second)
|
||||
}
|
||||
return dbError
|
||||
}
|
||||
41
driver/sqlx.go
Normal file
41
driver/sqlx.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// NewSQLxDB creates a *sqlx.DB with a backoff timer. By default 20 attempts
|
||||
// will be made, with a 1 second increasing interval.
|
||||
func NewSQLxDB(driver, conn string, opts ...ConnOption) (*sqlx.DB, error) {
|
||||
conf := &config{
|
||||
logger: log.NewNopLogger(),
|
||||
maxAttempts: defaultAttempts,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(conf)
|
||||
}
|
||||
db, err := sqlx.Open(driver, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var dbError error
|
||||
for attempts := 1; attempts <= conf.maxAttempts; attempts++ {
|
||||
dbError = db.Ping()
|
||||
if dbError == nil {
|
||||
break
|
||||
}
|
||||
sleep := time.Duration(attempts)
|
||||
conf.logger.Log("msg", fmt.Sprintf(
|
||||
"could not connect to %s: %v, sleeping %v", driver, dbError, sleep))
|
||||
time.Sleep(sleep * time.Second)
|
||||
}
|
||||
if dbError != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
Reference in New Issue
Block a user