-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy patherrors.go
More file actions
107 lines (89 loc) · 3.29 KB
/
Copy patherrors.go
File metadata and controls
107 lines (89 loc) · 3.29 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
package circuit
import (
"errors"
"fmt"
)
var errThrottledConcurrentCommands = (&circuitError{concurrencyLimitReached: true}).withMsg("throttling connections to command")
var errThrottledConcurrentFallbacks = (&circuitError{concurrencyLimitReached: true}).withMsg("throttling concurrency to fallbacks")
var errCircuitOpen = (&circuitError{circuitOpen: true}).withMsg("circuit is open")
// circuitError is used for internally generated errors
type circuitError struct {
concurrencyLimitReached bool
circuitOpen bool
// msg is the fully formatted Error() string, precomputed so the (shared, immutable) sentinel errors do not
// allocate on every Error() call.
msg string
}
// withMsg precomputes Error() (so the shared, immutable sentinels never allocate) and returns m for chaining.
func (m *circuitError) withMsg(msg string) *circuitError {
m.msg = fmt.Sprintf("%s: concurrencyReached=%t circuitOpen=%t", msg, m.concurrencyLimitReached, m.circuitOpen)
return m
}
var _ Error = &circuitError{}
// Error is the type of error returned by internal errors using the circuit library.
type Error interface {
error
// ConcurrencyLimitReached returns true if this error is because the concurrency limit has been reached.
ConcurrencyLimitReached() bool
// CircuitOpen returns true if this error is because the circuit is open.
CircuitOpen() bool
}
func (m *circuitError) Error() string {
return m.msg
}
func (m *circuitError) ConcurrencyLimitReached() bool {
return m.concurrencyLimitReached
}
func (m *circuitError) CircuitOpen() bool {
return m.circuitOpen
}
// BadRequest is implemented by an error returned by runFunc if you want to consider the requestor bad, not the circuit
// bad. See http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/exception/HystrixBadRequestException.html
// and https://github.com/Netflix/Hystrix/wiki/How-To-Use#error-propagation for information.
type BadRequest interface {
BadRequest() bool
}
// IsBadRequest returns true if the error is of type BadRequest, checking wrapped errors like errors.As.
func IsBadRequest(err error) bool {
if err == nil {
return false
}
// Fast paths first: this runs on every failed Execute (including the short-circuit/throttle shed path that
// matters most under overload), and reflective errors.As costs ~20x more plus an allocation.
switch e := err.(type) {
case *circuitError:
return false
case BadRequest:
return e.BadRequest()
case interface{ Unwrap() error }, interface{ Unwrap() []error }, interface{ As(interface{}) bool }:
var br BadRequest
return errors.As(err, &br) && br.BadRequest()
}
return false
}
// SimpleBadRequest is a simple wrapper for an error to mark it as a bad request
type SimpleBadRequest struct {
Err error
}
// Cause returns the wrapped error
func (s SimpleBadRequest) Cause() error {
return s.Err
}
// Unwrap returns the wrapped error so errors.Is / errors.As can see through a SimpleBadRequest
func (s SimpleBadRequest) Unwrap() error {
return s.Err
}
// Error returns the error message
func (s SimpleBadRequest) Error() string {
if s.Err == nil {
return "bad request"
}
return s.Err.Error()
}
// BadRequest always returns true
func (s SimpleBadRequest) BadRequest() bool {
return true
}
var _ error = &SimpleBadRequest{}
var _ BadRequest = &SimpleBadRequest{}
var _ error = &circuitError{}