mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Use retry func while trying to ping SQL datastore (#630)
* Use retry func while trying to ping SQL datastore - implements retry func specifically for SQL datastore ping - fmt fixes - using sqlx.Db.PingContext instead of sqlx.Db.Ping - propogate context to SQL datastore * Rely on context from ServerOpt * Consolidate log instances * Cleanup * Fix server usage in API tests
This commit is contained in:
committed by
Reed Allman
parent
4a85806544
commit
faaf5846ce
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fnproject/fn/api/common"
|
||||
"github.com/fnproject/fn/api/datastore/sql/migrations"
|
||||
"github.com/fnproject/fn/api/models"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
@@ -96,14 +97,15 @@ type sqlStore struct {
|
||||
|
||||
// New will open the db specified by url, create any tables necessary
|
||||
// and return a models.Datastore safe for concurrent usage.
|
||||
func New(url *url.URL) (models.Datastore, error) {
|
||||
return newDS(url)
|
||||
func New(ctx context.Context, url *url.URL) (models.Datastore, error) {
|
||||
return newDS(ctx, url)
|
||||
}
|
||||
|
||||
// for test methods, return concrete type, but don't expose
|
||||
func newDS(url *url.URL) (*sqlStore, error) {
|
||||
func newDS(ctx context.Context, url *url.URL) (*sqlStore, error) {
|
||||
driver := url.Scheme
|
||||
|
||||
log := common.Logger(ctx)
|
||||
// driver must be one of these for sqlx to work, double check:
|
||||
switch driver {
|
||||
case "postgres", "pgx", "mysql", "sqlite3":
|
||||
@@ -128,25 +130,25 @@ func newDS(url *url.URL) (*sqlStore, error) {
|
||||
|
||||
sqldb, err := sql.Open(driver, uri)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{"url": uri}).WithError(err).Error("couldn't open db")
|
||||
log.WithFields(logrus.Fields{"url": uri}).WithError(err).Error("couldn't open db")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := sqlx.NewDb(sqldb, driver)
|
||||
// force a connection and test that it worked
|
||||
err = db.Ping()
|
||||
err = pingWithRetry(ctx, 10, time.Second*1, db)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{"url": uri}).WithError(err).Error("couldn't ping db")
|
||||
log.WithFields(logrus.Fields{"url": uri}).WithError(err).Error("couldn't ping db")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxIdleConns := 256 // TODO we need to strip this out of the URL probably
|
||||
db.SetMaxIdleConns(maxIdleConns)
|
||||
logrus.WithFields(logrus.Fields{"max_idle_connections": maxIdleConns, "datastore": driver}).Info("datastore dialed")
|
||||
log.WithFields(logrus.Fields{"max_idle_connections": maxIdleConns, "datastore": driver}).Info("datastore dialed")
|
||||
|
||||
err = runMigrations(url.String(), checkExistence(db)) // original url string
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("error running migrations")
|
||||
log.WithError(err).Error("error running migrations")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -155,7 +157,7 @@ func newDS(url *url.URL) (*sqlStore, error) {
|
||||
db.SetMaxOpenConns(1)
|
||||
}
|
||||
for _, v := range tables {
|
||||
_, err = db.Exec(v)
|
||||
_, err = db.ExecContext(ctx, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -164,6 +166,17 @@ func newDS(url *url.URL) (*sqlStore, error) {
|
||||
return &sqlStore{db: db}, nil
|
||||
}
|
||||
|
||||
func pingWithRetry(ctx context.Context, attempts int, sleep time.Duration, db *sqlx.DB) (err error) {
|
||||
for i := 0; i < attempts; i++ {
|
||||
err = db.PingContext(ctx)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(sleep)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// checkExistence checks if tables have been created yet, it is not concerned
|
||||
// about the existence of the schema migration version (since migrations were
|
||||
// added to existing dbs, we need to know whether the db exists without migrations
|
||||
|
||||
Reference in New Issue
Block a user