From f79e21040743183c867e9fd4bf7e33694fa6dac4 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Fri, 19 Jun 2020 19:31:05 +0200 Subject: [PATCH] Improve transaction handling in github.com/titpetric/factory This is an ugly/temp update of vendored github.com/titpetric/factory. It fixes: - invalid savepoint rollback SQL syntax - err handling on rollback calls - inc. number of tries in case of a (dead)lock (from 3 to 64) - better backoff algo for sleep between retries --- .../github.com/titpetric/factory/database.go | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/vendor/github.com/titpetric/factory/database.go b/vendor/github.com/titpetric/factory/database.go index 95f0d5de1..3b4e35f83 100644 --- a/vendor/github.com/titpetric/factory/database.go +++ b/vendor/github.com/titpetric/factory/database.go @@ -235,6 +235,10 @@ func (r *DB) Begin() (err error) { // Transaction will create a transaction and invoke a callback func (r *DB) Transaction(callback func() error) (err error) { + // Max tries in case of a (dead)lock + // @todo should be configurable + const MAX_TRIES = 64 + var try int // Perform transaction statements @@ -250,7 +254,8 @@ func (r *DB) Transaction(callback func() error) (err error) { } try++ - if try > 3 { + // + if try > MAX_TRIES { r.logger.Log(r.ctx, fmt.Sprintf("Retried transaction %d times, aborting", try-1)) break } @@ -267,8 +272,15 @@ func (r *DB) Transaction(callback func() error) (err error) { // - 1213: deadlock found if cause.Number == 1205 || cause.Number == 1213 { r.logger.Log(r.ctx, "Retrying transaction", logger.NewField("try", try), logger.NewField("cause", cause)) - r.Rollback() - time.Sleep(50 * time.Millisecond) + + err = r.Rollback() + if err != nil { + r.logger.Log(r.ctx, "failed to rollback transaction", logger.NewField("err", err)) + return err + } + + // raise time to sleep on each try + time.Sleep(time.Millisecond * time.Duration(try * 50)) continue } @@ -277,7 +289,12 @@ func (r *DB) Transaction(callback func() error) (err error) { } if err != nil { - r.Rollback() + rerr := r.Rollback() + if rerr != nil { + r.logger.Log(r.ctx, "failed to rollback transaction", logger.NewField("err", rerr)) + return rerr + } + return err } return r.Commit() @@ -318,7 +335,7 @@ func (r *DB) Rollback() (err error) { r.inTx = 0 return nil } - if _, err = r.Exec(fmt.Sprintf("ROLLBACK SAVEPOINT sp_%d", r.inTx-1)); err != nil { + if _, err = r.Exec(fmt.Sprintf("ROLLBACK TO SAVEPOINT sp_%d", r.inTx-1)); err != nil { return errors.WithStack(err) } r.inTx--