Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BCDA-3710 - Resolve issues with stale db connections #600

Merged
merged 15 commits into from
Dec 16, 2020
Merged
7 changes: 4 additions & 3 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ load-fixtures:
$(MAKE) load-synthetic-suppression-data
$(MAKE) load-fixtures-ssas

# Since we've rebuilt the databases, we need to restart the worker and api
# to ensure it picks up connections to the new db instance.
# TODO (BCDA-3710) we should be able to remove this line once we have connection pooling on the worker
# Ensure components are started as expected
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still needed to keep this restart here because of issues uncovered in our CI process. It's caused by the database being dropped while the app is initializing.

Removing the TODO since the restart is not related to the restarting of the db instance.

docker-compose restart api worker ssas
sleep 5

Expand Down
53 changes: 49 additions & 4 deletions bcda/api/requests.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package api

import (
"context"
"fmt"
"net/url"
"regexp"
Expand Down Expand Up @@ -45,6 +46,11 @@ func NewHandler(resources []string, basePath string) *Handler {

h := &Handler{}

db := database.GetGORMDbConnection()
db.DB().SetMaxOpenConns(utils.GetEnvInt("BCDA_DB_MAX_OPEN_CONNS", 25))
db.DB().SetMaxIdleConns(utils.GetEnvInt("BCDA_DB_MAX_IDLE_CONNS", 25))
db.DB().SetConnMaxLifetime(time.Duration(utils.GetEnvInt("BCDA_DB_CONN_MAX_LIFETIME_MIN", 5)) * time.Minute)

queueDatabaseURL := os.Getenv("QUEUE_DATABASE_URL")
pgxcfg, err := pgx.ParseURI(queueDatabaseURL)
if err != nil {
Expand All @@ -59,6 +65,49 @@ func NewHandler(resources []string, basePath string) *Handler {
log.Fatal(err)
}

// With que-go locked to pgx v3, we need a mechanism that will allow us to
// discard bad connections in the pgxpool (see: https://github.com/jackc/pgx/issues/494)
// This implementation is based off of the "fix" that is present in v4
// (see: https://github.com/jackc/pgx/blob/v4.10.0/pgxpool/pool.go#L333)
// Use the same approach to validate the connection associated with the gorm client
Comment on lines +72 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea to link to resources explaining the implementation here


// If we implement a cleanup function on the handler,
// consider using context.WithCancel() to give us a hook to stop the goroutine
ctx := context.Background()
go func() {
ticker := time.NewTicker(10 * time.Second)
for {
select {
case <-ctx.Done():
ticker.Stop()
log.Debug("Stopping pgxpool checker")
return
case <-ticker.C:
log.Debug("Sending ping")
c, err := pgxpool.Acquire()
if err != nil {
log.Warnf("Failed to acquire connection %s", err.Error())
}
if err := c.Ping(ctx); err != nil {
log.Warnf("Failed to ping %s", err.Error())
}
pgxpool.Release(c)

c1, err := db.DB().Conn(ctx)
if err != nil {
log.Warnf("Failed to acquire connection %s", err.Error())
continue
}
if err := c1.PingContext(ctx); err != nil {
log.Warnf("Failed to ping %s", err.Error())
}
if err := c1.Close(); err != nil {
log.Warnf("Failed to close conection %s", err.Error())
}
}
}
}()

h.qc = que.NewClient(pgxpool)

cutoffDuration := time.Duration(utils.GetEnvInt("CCLF_CUTOFF_DATE_DAYS", 45)*24) * time.Hour
Expand All @@ -71,10 +120,6 @@ func NewHandler(resources []string, basePath string) *Handler {
log.Fatalf("Failed to parse RUNOUT_CLAIM_THRU_DATE '%s'. Err: %s", runoutClaimThru, err.Error())
}

db := database.GetGORMDbConnection()
db.DB().SetMaxOpenConns(utils.GetEnvInt("BCDA_DB_MAX_OPEN_CONNS", 25))
db.DB().SetMaxIdleConns(utils.GetEnvInt("BCDA_DB_MAX_IDLE_CONNS", 25))
db.DB().SetConnMaxLifetime(time.Duration(utils.GetEnvInt("BCDA_DB_CONN_MAX_LIFETIME_MIN", 5)) * time.Minute)
repository := postgres.NewRepository(db)
h.svc = models.NewService(repository, cutoffDuration, utils.GetEnvInt("BCDA_SUPPRESSION_LOOKBACK_DAYS", 60),
runoutCutoffDuration, runoutClaimThruDate,
Expand Down
2 changes: 2 additions & 0 deletions vendor/github.com/lib/pq/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 0 additions & 13 deletions vendor/github.com/lib/pq/.travis.sh

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 6 additions & 11 deletions vendor/github.com/lib/pq/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 0 additions & 29 deletions vendor/github.com/lib/pq/CONTRIBUTING.md

This file was deleted.

77 changes: 6 additions & 71 deletions vendor/github.com/lib/pq/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading