add utility package for establishing db driver connections (#51)

This commit is contained in:
Victor Vrantchan
2016-11-13 20:02:54 -05:00
committed by GitHub
parent 2751a79c86
commit 0c92a4ad8b
3 changed files with 147 additions and 0 deletions

38
driver/driver.go Normal file
View 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
View 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
View 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
}