diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index 0605b04e9..ce3c08c48 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -410,24 +410,22 @@ func (c *Command) Run(args []string) int { c.UI.Error(fmt.Errorf("Can't get schema manager: %w.", err).Error()) return base.CommandCliError } - if !c.Config.Controller.Database.SkipSharedLockAcquisition { - // This is an advisory lock on the DB which is released when the db session ends. - if err := sMan.SharedLock(c.Context); err != nil { - c.UI.Error(fmt.Errorf("Unable to gain shared access to the database: %w", err).Error()) - return base.CommandCliError - } - defer func() { - // The base context has already been canceled so we shouldn't use it here. - // 1 second is chosen so the shutdown is still responsive and this is a mostly - // non critical step since the lock should be released when the session with the - // database is closed. - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - if err := sMan.SharedUnlock(ctx); err != nil { - c.UI.Error(fmt.Errorf("Unable to release shared lock to the database: %w", err).Error()) - } - }() + // This is an advisory locks on the DB which is released when the db session ends. + if err := sMan.SharedLock(c.Context); err != nil { + c.UI.Error(fmt.Errorf("Unable to gain shared access to the database: %w", err).Error()) + return base.CommandCliError } + defer func() { + // The base context has already been canceled so we shouldn't use it here. + // 1 second is chosen so the shutdown is still responsive and this is a mostly + // non critical step since the lock should be released when the session with the + // database is closed. + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + if err := sMan.Close(ctx); err != nil { + c.UI.Error(fmt.Errorf("Unable to release shared lock to the database: %w", err).Error()) + } + }() ckState, err := sMan.CurrentState(c.Context) if err != nil { c.UI.Error(fmt.Errorf("Error checking schema state: %w", err).Error()) diff --git a/internal/db/schema/internal/postgres/postgres.go b/internal/db/schema/internal/postgres/postgres.go index e0b1c49ad..e0ed1000d 100644 --- a/internal/db/schema/internal/postgres/postgres.go +++ b/internal/db/schema/internal/postgres/postgres.go @@ -251,6 +251,11 @@ func (p *Postgres) Run(ctx context.Context, migration io.Reader, version int, ed return nil } +// Close closes the underlying Postgres database connection. +func (p *Postgres) Close() error { + return p.conn.Close() +} + var errOldMigrationTable = stderrors.New("old schema migration table") func (p *Postgres) schemaInitialized(ctx context.Context) (bool, error) { diff --git a/internal/db/schema/manager.go b/internal/db/schema/manager.go index a2d75e17e..95d042540 100644 --- a/internal/db/schema/manager.go +++ b/internal/db/schema/manager.go @@ -22,6 +22,7 @@ type driver interface { Lock(context.Context) error Unlock(context.Context) error UnlockShared(context.Context) error + Close() error // StartRun begins a transaction internal to the driver. StartRun(context.Context) error // CommitRun commits a transaction, if there is an error it should rollback the transaction. @@ -123,6 +124,18 @@ func (b *Manager) CurrentState(ctx context.Context) (*State, error) { return &dbS, nil } +// Close unlocks the database shared lock and closes the underlying +// database connection afterwards. +func (b *Manager) Close(ctx context.Context) error { + const op = "schema.(Manager).Close" + err := b.SharedUnlock(ctx) + if err != nil { + return errors.Wrap(ctx, err, op) + } + + return b.driver.Close() +} + // SharedLock attempts to obtain a shared lock on the database. This can fail // if an exclusive lock is already held. If the lock can't be obtained an // error is returned.