Check unique constraint errors when manually inserting migrations (#2712)

This should avoid unnecessary logging on startup if the migration (were
we need `InsertMigration`) was already executed.
This now checks for "unique constraint errors" for SQLite and Postgres
and fails the startup process if the migration couldn't be manually
inserted for some other reason.
This commit is contained in:
Till 2022-09-13 08:07:43 +02:00 committed by GitHub
parent 62afb936a5
commit 100fa9b235
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 40 additions and 24 deletions

View File

@ -155,5 +155,10 @@ func InsertMigration(ctx context.Context, db *sql.DB, migrationName string) erro
time.Now().Format(time.RFC3339), time.Now().Format(time.RFC3339),
internal.VersionString(), internal.VersionString(),
) )
// If the migration was already executed, we'll get a unique constraint error,
// return nil instead, to avoid unnecessary logging.
if IsUniqueConstraintViolationErr(err) {
return nil
}
return err return err
} }

View File

@ -12,12 +12,27 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build wasm //go:build !wasm
// +build wasm // +build !wasm
package sqlutil package sqlutil
// IsUniqueConstraintViolationErr no-ops for this architecture import (
"github.com/lib/pq"
"github.com/mattn/go-sqlite3"
)
// IsUniqueConstraintViolationErr returns true if the error is an unique_violation error
func IsUniqueConstraintViolationErr(err error) bool { func IsUniqueConstraintViolationErr(err error) bool {
switch e := err.(type) {
case *pq.Error:
return e.Code == "23505"
case pq.Error:
return e.Code == "23505"
case *sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
}
return false return false
} }

View File

@ -12,15 +12,20 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !wasm //go:build wasm
// +build !wasm // +build wasm
package sqlutil package sqlutil
import "github.com/lib/pq" import "github.com/mattn/go-sqlite3"
// IsUniqueConstraintViolationErr returns true if the error is a postgresql unique_violation error // IsUniqueConstraintViolationErr returns true if the error is an unique_violation error
func IsUniqueConstraintViolationErr(err error) bool { func IsUniqueConstraintViolationErr(err error) bool {
pqErr, ok := err.(*pq.Error) switch e := err.(type) {
return ok && pqErr.Code == "23505" case *sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
}
return false
} }

View File

@ -18,8 +18,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"errors" "errors"
"fmt"
"github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
@ -81,8 +80,7 @@ func executeMigration(ctx context.Context, db *sql.DB) error {
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed
if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil { if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil {
// not a fatal error, log and continue return fmt.Errorf("unable to manually insert migration '%s': %w", migrationName, err)
logrus.WithError(err).Warnf("unable to manually insert migration '%s'", migrationName)
} }
return nil return nil
} }

View File

@ -18,8 +18,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"errors" "errors"
"fmt"
"github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
@ -80,8 +79,7 @@ func executeMigration(ctx context.Context, db *sql.DB) error {
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed
if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil { if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil {
// not a fatal error, log and continue return fmt.Errorf("unable to manually insert migration '%s': %w", migrationName, err)
logrus.WithError(err).Warnf("unable to manually insert migration '%s'", migrationName)
} }
return nil return nil
} }

View File

@ -21,8 +21,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/sirupsen/logrus"
// Import the postgres database driver. // Import the postgres database driver.
_ "github.com/lib/pq" _ "github.com/lib/pq"
@ -79,8 +77,7 @@ func executeMigration(ctx context.Context, db *sql.DB) error {
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed
if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil { if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil {
// not a fatal error, log and continue return fmt.Errorf("unable to manually insert migration '%s': %w", migrationName, err)
logrus.WithError(err).Warnf("unable to manually insert migration '%s'", migrationName)
} }
return nil return nil
} }

View File

@ -22,7 +22,6 @@ import (
"fmt" "fmt"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
@ -87,8 +86,7 @@ func executeMigration(ctx context.Context, db *sql.DB) error {
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed if errors.Is(err, sql.ErrNoRows) { // migration was already executed, as the column was removed
if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil { if err = sqlutil.InsertMigration(ctx, db, migrationName); err != nil {
// not a fatal error, log and continue return fmt.Errorf("unable to manually insert migration '%s': %w", migrationName, err)
logrus.WithError(err).Warnf("unable to manually insert migration '%s'", migrationName)
} }
return nil return nil
} }