From 08bdaa5fd52a816db8299ad1430faaf93f897542 Mon Sep 17 00:00:00 2001 From: InfiniteStash <117855276+InfiniteStash@users.noreply.github.com> Date: Sun, 6 Feb 2022 21:23:53 +0100 Subject: [PATCH] Fix edit failing when pg transaction is aborted (#294) --- pkg/manager/edit/edit.go | 6 ++++++ pkg/sqlx/transaction.go | 26 +++++++++++++++++++++++--- pkg/txn/state.go | 1 + 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pkg/manager/edit/edit.go b/pkg/manager/edit/edit.go index d808bd3..904be03 100644 --- a/pkg/manager/edit/edit.go +++ b/pkg/manager/edit/edit.go @@ -120,6 +120,11 @@ func ApplyEdit(fac models.Repo, editID uuid.UUID, immediate bool) (*models.Edit, success := true if err := applyer.apply(); err != nil { + // Failed apply, so we reset the txn in case it was a postgres error which would block further queries + if err := fac.ResetTxn(); err != nil { + return fmt.Errorf("Failed to reset failed transaction: %w", err) + } + success = false commentID, _ := uuid.NewV4() text := "###### Edit application failed: ######\n" @@ -130,6 +135,7 @@ func ApplyEdit(fac models.Repo, editID uuid.UUID, immediate bool) (*models.Edit, } modUser := user.GetModUser(fac) comment := models.NewEditComment(commentID, modUser, edit, text) + if err := eqb.CreateComment(*comment); err != nil { return err } diff --git a/pkg/sqlx/transaction.go b/pkg/sqlx/transaction.go index 21a94b0..1bb18e0 100644 --- a/pkg/sqlx/transaction.go +++ b/pkg/sqlx/transaction.go @@ -2,6 +2,7 @@ package sqlx import ( "database/sql" + "fmt" "github.com/jmoiron/sqlx" "github.com/stashapp/stash-box/pkg/models" @@ -39,17 +40,18 @@ func (m *txnState) WithTxn(fn func() error) (err error) { m.tx = tx defer func() { + transaction := m.tx m.tx = nil //nolint:gocritic if p := recover(); p != nil { // a panic occurred, rollback and repanic - _ = tx.Rollback() + _ = transaction.Rollback() panic(p) } else if err != nil { // something went wrong, rollback - _ = tx.Rollback() + _ = transaction.Rollback() } else { - err = tx.Commit() + err = transaction.Commit() } }() @@ -57,6 +59,24 @@ func (m *txnState) WithTxn(fn func() error) (err error) { return } +func (m *txnState) ResetTxn() error { + if !m.InTxn() { + return fmt.Errorf("not in transaction") + } + + if err := m.tx.Rollback(); err != nil { + return err + } + + tx, err := m.rootDB.Beginx() + if err != nil { + return err + } + + m.tx = tx + return nil +} + func (m *txnState) InTxn() bool { return m.tx != nil } diff --git a/pkg/txn/state.go b/pkg/txn/state.go index e971f85..9549d68 100644 --- a/pkg/txn/state.go +++ b/pkg/txn/state.go @@ -14,6 +14,7 @@ type Mgr interface { type State interface { WithTxn(fn func() error) error InTxn() bool + ResetTxn() error } func MustBeIn(m State) {