-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.go
More file actions
109 lines (92 loc) · 2.75 KB
/
errors.go
File metadata and controls
109 lines (92 loc) · 2.75 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package rcpx
import (
"errors"
"fmt"
)
var (
// ErrNoUpstreams is returned when Config.Upstreams is empty.
ErrNoUpstreams = errors.New("rcpx: no upstreams")
// ErrNoEligibleUpstreams indicates that no upstreams were eligible to try
// (e.g., all cooling down).
ErrNoEligibleUpstreams = errors.New("rcpx: no eligible upstreams")
// ErrBodyTooLarge is returned when the request body exceeds the configured cap.
ErrBodyTooLarge = errors.New("rcpx: request body too large")
// ErrBodyUnreadable is returned when the request body cannot be read.
ErrBodyUnreadable = errors.New("rcpx: request body unreadable")
)
// AllUpstreamsFailedError is returned when no upstream attempt succeeded.
//
// For Attempted==0, Unwrap() returns ErrNoEligibleUpstreams.
type AllUpstreamsFailedError struct {
Attempted int
SkippedCooldown int
// Failures are recorded in attempt order (one per attempt; bounded).
Failures []AttemptFailure
}
func (e *AllUpstreamsFailedError) Error() string {
if e == nil {
return "rcpx: all upstreams failed"
}
if e.Attempted == 0 {
return "rcpx: no eligible upstreams"
}
cause := e.Unwrap()
if cause == nil {
return fmt.Sprintf("rcpx: all upstreams failed (attempted=%d)", e.Attempted)
}
return fmt.Sprintf("rcpx: all upstreams failed (attempted=%d): %v", e.Attempted, cause)
}
// Unwrap returns the last failure cause, or ErrNoEligibleUpstreams when no
// attempts were made.
func (e *AllUpstreamsFailedError) Unwrap() error {
if e == nil {
return nil
}
if e.Attempted == 0 {
return ErrNoEligibleUpstreams
}
for i := len(e.Failures) - 1; i >= 0; i-- {
if err := e.Failures[i].Err; err != nil {
return err
}
}
return nil
}
// AttemptFailure records a failed attempt.
type AttemptFailure struct {
Upstream string
Method string
Batch bool
StatusCode int
Err error
Retryable bool // whether rcpx continued after this attempt
}
// NonIdempotentBlockedError is returned when a request classified as
// non-idempotent would otherwise retry/failover but AllowNonIdempotent is false.
//
// It wraps the underlying failure cause.
type NonIdempotentBlockedError struct {
Outcome AttemptOutcome
Cause error
}
func (e *NonIdempotentBlockedError) Error() string {
if e == nil {
return "rcpx: non-idempotent request blocked"
}
if e.Outcome.Method != "" {
if e.Cause != nil {
return fmt.Sprintf("rcpx: non-idempotent request blocked (%s): %v", e.Outcome.Method, e.Cause)
}
return fmt.Sprintf("rcpx: non-idempotent request blocked (%s)", e.Outcome.Method)
}
if e.Cause != nil {
return fmt.Sprintf("rcpx: non-idempotent request blocked: %v", e.Cause)
}
return "rcpx: non-idempotent request blocked"
}
func (e *NonIdempotentBlockedError) Unwrap() error {
if e == nil {
return nil
}
return e.Cause
}