-
Notifications
You must be signed in to change notification settings - Fork 257
/
slqerrors.go
89 lines (72 loc) · 2.41 KB
/
slqerrors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package pool
import (
"errors"
"fmt"
"github.com/jackc/pgx/v5/pgconn"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/authzed/spicedb/pkg/spiceerrors"
)
const (
// https://www.cockroachlabs.com/docs/stable/common-errors.html#restart-transaction
CrdbRetryErrCode = "40001"
// https://www.cockroachlabs.com/docs/stable/common-errors.html#result-is-ambiguous
CrdbAmbiguousErrorCode = "40003"
// https://www.cockroachlabs.com/docs/stable/node-shutdown.html#connection-retry-loop
CrdbServerNotAcceptingClients = "57P01"
// Error when SqlState is unknown
CrdbUnknownSQLState = "XXUUU"
// Error message encountered when crdb nodes have large clock skew
CrdbClockSkewMessage = "cannot specify timestamp in the future"
)
// MaxRetryError is returned when the retry budget is exhausted.
type MaxRetryError struct {
MaxRetries uint8
LastErr error
}
func (e *MaxRetryError) Error() string {
if e.MaxRetries == 0 {
return "retries disabled: " + e.LastErr.Error()
}
return fmt.Sprintf("max retries reached (%d): %s", e.MaxRetries, e.LastErr.Error())
}
func (e *MaxRetryError) Unwrap() error { return e.LastErr }
func (e *MaxRetryError) GRPCStatus() *status.Status {
s, ok := status.FromError(e.Unwrap())
if !ok {
return nil
}
return s
}
// ResettableError is an error that we think may succeed if retried against a new connection.
type ResettableError struct {
Err error
}
func (e *ResettableError) Error() string { return "resettable error" + ": " + e.Err.Error() }
func (e *ResettableError) Unwrap() error { return e.Err }
func (e *ResettableError) GRPCStatus() *status.Status {
return spiceerrors.WithCodeAndDetails(
e.Unwrap(),
codes.Unavailable, // return unavailable so clients are know it's ok to retry
)
}
// RetryableError is an error that can be retried against the existing connection.
type RetryableError struct {
Err error
}
func (e *RetryableError) Error() string { return "retryable error" + ": " + e.Err.Error() }
func (e *RetryableError) Unwrap() error { return e.Err }
func (e *RetryableError) GRPCStatus() *status.Status {
return spiceerrors.WithCodeAndDetails(
e.Unwrap(),
codes.Unavailable, // return unavailable so clients are know it's ok to retry
)
}
// sqlErrorCode attempts to extract the crdb error code from the error state.
func sqlErrorCode(err error) string {
var pgerr *pgconn.PgError
if !errors.As(err, &pgerr) {
return ""
}
return pgerr.SQLState()
}