Skip to content

Commit

Permalink
Serializable failure with recursion for DoTransaction on this error, …
Browse files Browse the repository at this point in the history
…and transaction aborted error handled (#26)

Serializable failure with recursion for DoTransaction on this error, and
transaction aborted error handled
  • Loading branch information
ice-myles authored Jan 17, 2024
1 parent 9931ca8 commit 042493c
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 6 deletions.
20 changes: 19 additions & 1 deletion connectors/storage/v2/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package storage
import (
"context"
"strings"
stdlibtime "time"

"github.com/cenkalti/backoff/v4"
"github.com/georgysavva/scany/v2/pgxscan"
Expand Down Expand Up @@ -38,6 +39,11 @@ func DoInTransaction(ctx context.Context, db *DB, fn func(conn QueryExecer) erro
return nil, backoff.Permanent(err) //nolint:wrapcheck // Not needed.
}
})
if err != nil && (errors.Is(err, ErrSerializationFailure) || errors.Is(err, ErrTxAborted)) {
stdlibtime.Sleep(10 * stdlibtime.Millisecond)

return DoInTransaction(ctx, db, fn)
}

return err
}
Expand Down Expand Up @@ -172,7 +178,10 @@ func IsUnexpected(err error) bool {
!IsErr(err, ErrRelationNotFound) &&
!IsErr(err, ErrNotFound) &&
!IsErr(err, ErrCheckFailed) &&
!IsErr(err, ErrRelationInUse)
!IsErr(err, ErrRelationInUse) &&
!IsErr(err, ErrSerializationFailure) &&
!IsErr(err, ErrTxAborted) &&
!IsErr(err, ErrExclusionViolation)
}

func parseDBError(err error) error { //nolint:funlen // .
Expand Down Expand Up @@ -206,6 +215,15 @@ func parseDBError(err error) error { //nolint:funlen // .

return terror.New(ErrCheckFailed, map[string]any{"column": column})
}
if dbErr.SQLState() == "40001" {
return ErrSerializationFailure
}
if dbErr.SQLState() == "25P02" {
return ErrTxAborted
}
if dbErr.SQLState() == "23P01" {
return ErrExclusionViolation
}

return err
}
Expand Down
13 changes: 8 additions & 5 deletions connectors/storage/v2/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import (
// Public API.

var (
ErrNotFound = errors.New("not found")
ErrRelationNotFound = errors.New("relation not found")
ErrRelationInUse = errors.New("relation in use")
ErrDuplicate = errors.New("duplicate")
ErrCheckFailed = errors.New("check failed")
ErrNotFound = errors.New("not found")
ErrRelationNotFound = errors.New("relation not found")
ErrRelationInUse = errors.New("relation in use")
ErrDuplicate = errors.New("duplicate")
ErrCheckFailed = errors.New("check failed")
ErrSerializationFailure = errors.New("serialization failure")
ErrTxAborted = errors.New("transaction aborted")
ErrExclusionViolation = errors.New("exclusion violation")
)

type (
Expand Down
15 changes: 15 additions & 0 deletions connectors/storage/v2/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ice-blockchain/wintr/terror"
)
Expand Down Expand Up @@ -140,3 +141,17 @@ $$ LANGUAGE plpgsql;`
return nil
}))
}

func TestStopWhenTxAborted(t *testing.T) {
t.Parallel()
db := MustConnect(context.Background(), "", "self")
require.NotNil(t, db)

err := DoInTransaction(context.Background(), db, func(tx QueryExecer) error {
_, gErr := Get[bool](context.Background(), tx, `SELECT $1 + $2`, 1, "2")

return gErr
})
require.ErrorIs(t, err, ErrTxAborted)
require.NoError(t, db.Close())
}

0 comments on commit 042493c

Please sign in to comment.