3
0

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
This commit is contained in:
Denis Arh 2020-06-19 19:31:05 +02:00
parent 1397e8eeb5
commit f79e210407

View File

@ -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--