mirror of
https://github.com/foomo/keel.git
synced 2025-10-16 12:35:34 +00:00
feat: introduced ErrIgnoreSuccessfulness
This commit is contained in:
parent
8f946bc5b0
commit
eea4aa4ab7
@ -20,6 +20,9 @@ var (
|
||||
// RoundTripware. It wraps the two gobreaker errors (ErrTooManyRequests & ErrOpenState) so only one comparison is
|
||||
// needed
|
||||
ErrCircuitBreaker = errors.New("circuit breaker triggered")
|
||||
|
||||
// ErrIgnoreSuccessfulness
|
||||
ErrIgnoreSuccessfulness = errors.New("ignored successfulness")
|
||||
)
|
||||
|
||||
// CircuitBreakerSettings is a copy of the gobreaker.Settings, except that the IsSuccessful function is omitted since we
|
||||
@ -51,7 +54,7 @@ type CircuitBreakerSettings struct {
|
||||
type CircuitBreakerOptions struct {
|
||||
Counter syncint64.Counter
|
||||
|
||||
IsSuccessful func(err error, req *http.Request, resp *http.Response) (e error, ignore bool)
|
||||
IsSuccessful func(err error, req *http.Request, resp *http.Response) error
|
||||
CopyReqBody bool
|
||||
CopyRespBody bool
|
||||
}
|
||||
@ -60,8 +63,8 @@ func NewDefaultCircuitBreakerOptions() *CircuitBreakerOptions {
|
||||
return &CircuitBreakerOptions{
|
||||
Counter: nil,
|
||||
|
||||
IsSuccessful: func(err error, req *http.Request, resp *http.Response) (e error, ignore bool) {
|
||||
return err, false
|
||||
IsSuccessful: func(err error, req *http.Request, resp *http.Response) error {
|
||||
return err
|
||||
},
|
||||
CopyReqBody: false,
|
||||
CopyRespBody: false,
|
||||
@ -91,7 +94,7 @@ func CircuitBreakerWithMetric(
|
||||
}
|
||||
|
||||
func CircuitBreakerWithIsSuccessful(
|
||||
isSuccessful func(err error, req *http.Request, resp *http.Response) (e error, ignore bool),
|
||||
isSuccessful func(err error, req *http.Request, resp *http.Response) (e error),
|
||||
copyReqBody bool,
|
||||
copyRespBody bool,
|
||||
) CircuitBreakerOption {
|
||||
@ -144,15 +147,15 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
|
||||
|
||||
var resp *http.Response
|
||||
// wrap the error in case it was produced because of the circuit breaker being (half-)open
|
||||
if errors.Is(gobreaker.ErrTooManyRequests, err) || errors.Is(gobreaker.ErrOpenState, err) {
|
||||
if errors.Is(err, gobreaker.ErrTooManyRequests) || errors.Is(err, gobreaker.ErrOpenState) {
|
||||
err = keelerrors.NewWrappedError(ErrCircuitBreaker, err)
|
||||
} else if err != nil {
|
||||
l.Error("unexpected error in circuit breaker",
|
||||
log.FError(err),
|
||||
zap.String("from", fromState.String()),
|
||||
zap.String("state", fromState.String()),
|
||||
)
|
||||
} else {
|
||||
//continue with the middleware chain
|
||||
// continue with the middleware chain
|
||||
resp, err = next(r)
|
||||
|
||||
var respCopy *http.Response
|
||||
@ -168,9 +171,7 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
|
||||
}
|
||||
}
|
||||
|
||||
var ignore bool
|
||||
err, ignore = o.IsSuccessful(err, reqCopy, respCopy)
|
||||
if !ignore {
|
||||
if err = o.IsSuccessful(err, reqCopy, respCopy); !errors.Is(err, ErrIgnoreSuccessfulness) {
|
||||
done(err == nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,11 +60,11 @@ func TestCircuitBreaker(t *testing.T) {
|
||||
keelhttp.HTTPClientWithRoundTripware(l,
|
||||
roundtripware.CircuitBreaker(cbSettings,
|
||||
roundtripware.CircuitBreakerWithIsSuccessful(
|
||||
func(err error, req *http.Request, resp *http.Response) (error, bool) {
|
||||
func(err error, req *http.Request, resp *http.Response) error {
|
||||
if resp.StatusCode >= http.StatusInternalServerError {
|
||||
return errors.New("invalid status code"), false
|
||||
return errors.New("invalid status code")
|
||||
}
|
||||
return nil, false
|
||||
return nil
|
||||
}, false, false,
|
||||
),
|
||||
),
|
||||
@ -148,7 +148,7 @@ func TestCircuitBreakerCopyBodies(t *testing.T) {
|
||||
keelhttp.HTTPClientWithRoundTripware(l,
|
||||
roundtripware.CircuitBreaker(cbSettings,
|
||||
roundtripware.CircuitBreakerWithIsSuccessful(
|
||||
func(err error, req *http.Request, resp *http.Response) (error, bool) {
|
||||
func(err error, req *http.Request, resp *http.Response) error {
|
||||
// read the bodies
|
||||
_, errRead := io.ReadAll(req.Body)
|
||||
require.NoError(t, errRead)
|
||||
@ -159,7 +159,7 @@ func TestCircuitBreakerCopyBodies(t *testing.T) {
|
||||
// also try to close one of the bodies (should also be handled by the RoundTripware)
|
||||
req.Body.Close()
|
||||
|
||||
return err, false
|
||||
return err
|
||||
}, true, true,
|
||||
),
|
||||
),
|
||||
@ -204,14 +204,14 @@ func TestCircuitBreakerReadFromNotCopiedBodies(t *testing.T) {
|
||||
keelhttp.HTTPClientWithRoundTripware(l,
|
||||
roundtripware.CircuitBreaker(cbSettings,
|
||||
roundtripware.CircuitBreakerWithIsSuccessful(
|
||||
func(err error, req *http.Request, resp *http.Response) (error, bool) {
|
||||
func(err error, req *http.Request, resp *http.Response) error {
|
||||
// read the bodies
|
||||
_, errRead := io.ReadAll(req.Body)
|
||||
if errRead != nil {
|
||||
return errRead, false
|
||||
return errRead
|
||||
}
|
||||
|
||||
return err, false
|
||||
return err
|
||||
}, false, true,
|
||||
),
|
||||
),
|
||||
@ -232,14 +232,14 @@ func TestCircuitBreakerReadFromNotCopiedBodies(t *testing.T) {
|
||||
keelhttp.HTTPClientWithRoundTripware(l,
|
||||
roundtripware.CircuitBreaker(cbSettings,
|
||||
roundtripware.CircuitBreakerWithIsSuccessful(
|
||||
func(err error, req *http.Request, resp *http.Response) (error, bool) {
|
||||
func(err error, req *http.Request, resp *http.Response) error {
|
||||
// read the bodies
|
||||
_, errRead := io.ReadAll(resp.Body)
|
||||
if errRead != nil {
|
||||
return errRead, false
|
||||
return errRead
|
||||
}
|
||||
|
||||
return err, false
|
||||
return err
|
||||
}, true, false,
|
||||
),
|
||||
),
|
||||
@ -280,11 +280,11 @@ func TestCircuitBreakerInterval(t *testing.T) {
|
||||
},
|
||||
},
|
||||
roundtripware.CircuitBreakerWithIsSuccessful(
|
||||
func(err error, req *http.Request, resp *http.Response) (error, bool) {
|
||||
func(err error, req *http.Request, resp *http.Response) error {
|
||||
if resp.StatusCode >= http.StatusInternalServerError {
|
||||
return errors.New("invalid status code"), false
|
||||
return errors.New("invalid status code")
|
||||
}
|
||||
return nil, false
|
||||
return nil
|
||||
}, false, false,
|
||||
),
|
||||
),
|
||||
@ -343,14 +343,14 @@ func TestCircuitBreakerIgnore(t *testing.T) {
|
||||
keelhttp.HTTPClientWithRoundTripware(l,
|
||||
roundtripware.CircuitBreaker(cbSettings,
|
||||
roundtripware.CircuitBreakerWithIsSuccessful(
|
||||
func(err error, req *http.Request, resp *http.Response) (error, bool) {
|
||||
func(err error, req *http.Request, resp *http.Response) error {
|
||||
if req.Method == http.MethodGet {
|
||||
return errors.New("some ignored error"), true
|
||||
return roundtripware.ErrIgnoreSuccessfulness
|
||||
}
|
||||
if resp.StatusCode >= http.StatusInternalServerError {
|
||||
return errors.New("invalid status code"), false
|
||||
return errors.New("invalid status code")
|
||||
}
|
||||
return nil, false
|
||||
return nil
|
||||
}, false, false,
|
||||
),
|
||||
),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user