chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package outbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
// retryableError is the explicit boundary between a temporary dependency
|
||||
// failure and a permanent job failure. Handlers must opt in by wrapping an
|
||||
// error with Retryable unless the infrastructure error is independently
|
||||
// recognizable as a timeout, network interruption or transient PostgreSQL
|
||||
// condition.
|
||||
type retryableError struct{ cause error }
|
||||
|
||||
func (e retryableError) Error() string { return e.cause.Error() }
|
||||
func (e retryableError) Unwrap() error { return e.cause }
|
||||
|
||||
// Retryable marks an error as safe to execute again with the same idempotency
|
||||
// boundary. A nil error remains nil so callers can wrap return values directly.
|
||||
func Retryable(err error) error {
|
||||
if err == nil || IsRetryable(err) {
|
||||
return err
|
||||
}
|
||||
return retryableError{cause: err}
|
||||
}
|
||||
|
||||
// IsRetryable deliberately keeps the automatic allow-list narrow. Validation,
|
||||
// unsupported state and malformed payload errors are permanent by default.
|
||||
func IsRetryable(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
var marked retryableError
|
||||
if errors.As(err, &marked) {
|
||||
return true
|
||||
}
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return true
|
||||
}
|
||||
var networkError net.Error
|
||||
if errors.As(err, &networkError) && (networkError.Timeout() || networkError.Temporary()) {
|
||||
return true
|
||||
}
|
||||
if pgconn.SafeToRetry(err) {
|
||||
return true
|
||||
}
|
||||
var postgresError *pgconn.PgError
|
||||
if !errors.As(err, &postgresError) {
|
||||
return false
|
||||
}
|
||||
// Connection, transaction rollback, resource exhaustion, lock-not-available
|
||||
// and administrator restart conditions can succeed on a later attempt.
|
||||
class := ""
|
||||
if len(postgresError.Code) >= 2 {
|
||||
class = postgresError.Code[:2]
|
||||
}
|
||||
return class == "08" || class == "40" || class == "53" ||
|
||||
postgresError.Code == "55P03" || postgresError.Code == "57P01" ||
|
||||
postgresError.Code == "57P02" || postgresError.Code == "57P03"
|
||||
}
|
||||
Reference in New Issue
Block a user