Skip to content

Commit

Permalink
feat: use higher DB timeouts for migrations
Browse files Browse the repository at this point in the history
Some queries in migrations on databases with full network state might take
longer than the configured database timeouts. To avoid the need for
manually updating the database timeouts in config for the migration,
always use higher timeouts when running migrations.
  • Loading branch information
ptrus committed Mar 24, 2022
1 parent f1456ce commit c34e4aa
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 12 deletions.
18 changes: 14 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func truncateExec(cmd *cobra.Command, args []string) error {
}

// Initialize db.
db, err := psql.InitDB(ctx, cfg.Database)
db, err := psql.InitDB(ctx, cfg.Database, true)
if err != nil {
logger.Error("failed to initialize db", "err", err)
return err
Expand Down Expand Up @@ -141,7 +141,7 @@ func migrateExec(cmd *cobra.Command, args []string) error {
logger := logging.GetLogger("migrate-db")

// Initialize db.
db, err := psql.InitDB(ctx, cfg.Database)
db, err := psql.InitDB(ctx, cfg.Database, true)
if err != nil {
logger.Error("failed to initialize db", "err", err)
return err
Expand Down Expand Up @@ -188,8 +188,8 @@ func runRoot() error {
// Create the runtime client with account module query helpers.
rc := client.New(conn, runtimeID)

// Initialize db
db, err := psql.InitDB(ctx, cfg.Database)
// Initialize db for migrations (higher timeouts).
db, err := psql.InitDB(ctx, cfg.Database, true)
if err != nil {
logger.Error("failed to initialize db", "err", err)
return err
Expand All @@ -198,6 +198,16 @@ func runRoot() error {
if err = db.RunMigrations(ctx); err != nil {
return fmt.Errorf("failed to migrate DB: %w", err)
}
if err = db.DB.(*bun.DB).DB.Close(); err != nil {
return fmt.Errorf("failed to close migrations DB: %w", err)
}

// Initialize db again, now with configured timeouts.
db, err = psql.InitDB(ctx, cfg.Database, false)
if err != nil {
logger.Error("failed to initialize db", "err", err)
return err
}

// Create Indexer
f := indexer.NewIndexBackend()
Expand Down
35 changes: 29 additions & 6 deletions storage/psql/psql.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,50 @@ import (
"github.com/oasisprotocol/emerald-web3-gateway/storage"
)

// Long timeout used when database is opened with long timeouts option enabled.
// XXX: the driver does not support unlimited timeouts, so set long enough that
// should cover all reasonable future cases.
var longReadWriteTimeout = time.Hour * 12

type PostDB struct {
DB bun.IDB
}

// InitDB creates postgresql db instance.
func InitDB(ctx context.Context, cfg *conf.DatabaseConfig) (*PostDB, error) {
func InitDB(ctx context.Context, cfg *conf.DatabaseConfig, longTimeouts bool) (*PostDB, error) {
if cfg == nil {
return nil, errors.New("nil configuration")
}

pgConn := pgdriver.NewConnector(
readTimeout := time.Duration(cfg.ReadTimeout) * time.Second
writeTimeout := time.Duration(cfg.WriteTimeout) * time.Second
opts := []pgdriver.Option{
pgdriver.WithAddr(fmt.Sprintf("%v:%v", cfg.Host, cfg.Port)),
pgdriver.WithDatabase(cfg.DB),
pgdriver.WithUser(cfg.User),
pgdriver.WithPassword(cfg.Password),
pgdriver.WithTLSConfig(nil),
pgdriver.WithDialTimeout(time.Duration(cfg.DialTimeout)*time.Second),
pgdriver.WithReadTimeout(time.Duration(cfg.ReadTimeout)*time.Second),
pgdriver.WithWriteTimeout(time.Duration(cfg.WriteTimeout)*time.Second))
pgdriver.WithDialTimeout(time.Duration(cfg.DialTimeout) * time.Second),
}

// Set read/write timeouts.
switch longTimeouts {
case false:
opts = append(opts,
pgdriver.WithReadTimeout(readTimeout),
pgdriver.WithWriteTimeout(writeTimeout),
)
case true:
// Increase write/read timeouts if DB is being opened for migrations/manual actions.
if longReadWriteTimeout > readTimeout {
opts = append(opts, pgdriver.WithReadTimeout(longReadWriteTimeout))
}
if longReadWriteTimeout > writeTimeout {
opts = append(opts, pgdriver.WithWriteTimeout(longReadWriteTimeout))
}
}

// open
pgConn := pgdriver.NewConnector(opts...)
sqlDB := sql.OpenDB(pgConn)
maxOpenConns := cfg.MaxOpenConns
if maxOpenConns == 0 {
Expand Down
2 changes: 1 addition & 1 deletion storage/psql/psql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestMain(m *testing.M) {
var err error
ctx := context.Background()
tests.MustInitConfig()
db, err = InitDB(ctx, tests.TestsConfig.Database)
db, err = InitDB(ctx, tests.TestsConfig.Database, false)
if err != nil {
log.Println(`It seems database failed to initialize. Do you have PostgreSQL running? If not, you can run
docker run -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p 5432:5432 -d postgres`)
Expand Down
12 changes: 11 additions & 1 deletion tests/rpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
oasisTesting "github.com/oasisprotocol/oasis-sdk/client-sdk/go/testing"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
"github.com/stretchr/testify/require"
"github.com/uptrace/bun"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

Expand Down Expand Up @@ -125,13 +126,22 @@ func Setup() error {

// Initialize db.
ctx := context.Background()
db, err = psql.InitDB(ctx, tests.TestsConfig.Database)
db, err = psql.InitDB(ctx, tests.TestsConfig.Database, true)
if err != nil {
return fmt.Errorf("failed to initialize DB: %w", err)
}
if err = db.RunMigrations(ctx); err != nil {
return fmt.Errorf("failed to migrate DB: %w", err)
}
if err = db.DB.(*bun.DB).DB.Close(); err != nil {
return fmt.Errorf("failed to close migrations DB: %w", err)
}

// Initialize db again, now with configured timeouts.
db, err = psql.InitDB(ctx, tests.TestsConfig.Database, false)
if err != nil {
return err
}

// Create Indexer.
f := indexer.NewIndexBackend()
Expand Down

0 comments on commit c34e4aa

Please sign in to comment.