From e8f1b88d37ffc20a353e4491f76c2e64060bc3f2 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Thu, 15 Mar 2018 16:53:13 +0100 Subject: [PATCH 1/3] Use Request context for HTTPClient.Do If the context is cancelled on the request the breaker considers that an error. Instead of creating a new context, we use the one provided on the http.Request, which returns context.BackGround if none is set. --- client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index e91c52b..3127e07 100644 --- a/client.go +++ b/client.go @@ -94,7 +94,8 @@ func (c *HTTPClient) Do(req *http.Request) (*http.Response, error) { var resp *http.Response var err error breaker := c.breakerLookup(req.URL.String()) - err = breaker.Call(func() error { + ctx := req.Context() + err = breaker.CallContext(ctx, func() error { resp, err = c.Client.Do(req) return err }, c.timeout) From 1d961865afddae95b555549f393f6f387cae7475 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Tue, 25 Sep 2018 15:48:03 +0200 Subject: [PATCH 2/3] Don't break on deadline exceeded. --- circuitbreaker.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/circuitbreaker.go b/circuitbreaker.go index 620cd94..9636a5b 100644 --- a/circuitbreaker.go +++ b/circuitbreaker.go @@ -361,7 +361,9 @@ func (cb *Breaker) CallContext(ctx context.Context, circuit func() error, timeou } if err != nil { - if ctx.Err() != context.Canceled { + switch ctx.Err() { + case context.Canceled, context.DeadlineExceeded: + default: cb.Fail() } return err From 71b1aba38de5e8059c5aed541b19926bb63d22dc Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Tue, 25 Sep 2018 15:59:37 +0200 Subject: [PATCH 3/3] Report error if breaker is also timed out. --- circuitbreaker.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/circuitbreaker.go b/circuitbreaker.go index 9636a5b..f7288a6 100644 --- a/circuitbreaker.go +++ b/circuitbreaker.go @@ -360,17 +360,23 @@ func (cb *Breaker) CallContext(ctx context.Context, circuit func() error, timeou } } - if err != nil { - switch ctx.Err() { - case context.Canceled, context.DeadlineExceeded: - default: + if err == nil { + cb.Success() + return nil + } + + switch ctx.Err() { + case context.Canceled: + case context.DeadlineExceeded: + // If the breaker timed out as well, report that, + // otherwise consider it "neutral". + if err == ErrBreakerTimeout { cb.Fail() } - return err + default: + cb.Fail() } - - cb.Success() - return nil + return err } // state returns the state of the TrippableBreaker. The states available are: