sqldb: improve serialization error handling

This commit is contained in:
Alex Akselrod
2024-11-06 11:29:47 -08:00
parent c01dcc2be7
commit 780c271b80
6 changed files with 44 additions and 16 deletions

View File

@@ -22,7 +22,7 @@ const (
// DefaultNumTxRetries is the default number of times we'll retry a
// transaction if it fails with an error that permits transaction
// repetition.
DefaultNumTxRetries = 10
DefaultNumTxRetries = 20
// DefaultRetryDelay is the default delay between retries. This will be
// used to generate a random delay between 0 and this value.

View File

@@ -17,6 +17,16 @@ var (
// ErrRetriesExceeded is returned when a transaction is retried more
// than the max allowed valued without a success.
ErrRetriesExceeded = errors.New("db tx retries exceeded")
// postgresErrMsgs are strings that signify retriable errors resulting
// from serialization failures.
postgresErrMsgs = []string{
"could not serialize access",
"current transaction is aborted",
"not enough elements in RWConflictPool",
"deadlock detected",
"commit unexpectedly resulted in rollback",
}
)
// MapSQLError attempts to interpret a given error as a database agnostic SQL
@@ -41,10 +51,11 @@ func MapSQLError(err error) error {
// Sometimes the error won't be properly wrapped, so we'll need to
// inspect raw error itself to detect something we can wrap properly.
// This handles a postgres variant of the error.
const postgresErrMsg = "could not serialize access"
if strings.Contains(err.Error(), postgresErrMsg) {
return &ErrSerializationError{
DBError: err,
for _, postgresErrMsg := range postgresErrMsgs {
if strings.Contains(err.Error(), postgresErrMsg) {
return &ErrSerializationError{
DBError: err,
}
}
}
@@ -105,6 +116,20 @@ func parsePostgresError(pqErr *pgconn.PgError) error {
DBError: pqErr,
}
// In failed SQL transaction because we didn't catch a previous
// serialization error, so return this one as a serialization error.
case pgerrcode.InFailedSQLTransaction:
return &ErrSerializationError{
DBError: pqErr,
}
// Deadlock detedted because of a serialization error, so return this
// one as a serialization error.
case pgerrcode.DeadlockDetected:
return &ErrSerializationError{
DBError: pqErr,
}
default:
return fmt.Errorf("unknown postgres error: %w", pqErr)
}