From 781bc3b39d7f885f3b97f9e184a064fc05302e20 Mon Sep 17 00:00:00 2001 From: Jack Lindamood Date: Tue, 27 Aug 2019 10:20:05 -0700 Subject: [PATCH 1/2] Error: add Error type. Clarify how to check for internal circuit errors Resolves #77 --- v3/circuit.go | 2 ++ v3/errors.go | 9 +++++++++ v3/example_test.go | 8 ++++++++ v3/metrics/statsdmetrics/statsd.go | 2 +- v3/metrics/statsdmetrics/statsd_test.go | 5 +++-- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/v3/circuit.go b/v3/circuit.go index 40d1bb8..79607e5 100644 --- a/v3/circuit.go +++ b/v3/circuit.go @@ -218,6 +218,8 @@ func (c *Circuit) Run(ctx context.Context, runFunc func(context.Context) error) } // Execute the circuit. Prefer this over Go. Similar to http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#execute-- +// The returned error will either be the result of runFunc, the result of fallbackFunc, or an internal library error. +// Internal library errors will match the interface Error and you can use type casting to check this. func (c *Circuit) Execute(ctx context.Context, runFunc func(context.Context) error, fallbackFunc func(context.Context, error) error) error { if c.isEmptyOrNil() || c.threadSafeConfig.CircuitBreaker.Disabled.Get() { return runFunc(ctx) diff --git a/v3/errors.go b/v3/errors.go index cad9b8b..dfa95ce 100644 --- a/v3/errors.go +++ b/v3/errors.go @@ -12,6 +12,15 @@ type circuitError struct { msg string } +// 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 fmt.Sprintf("%s: concurrencyReached=%t circuitOpen=%t", m.msg, m.ConcurrencyLimitReached(), m.CircuitOpen()) } diff --git a/v3/example_test.go b/v3/example_test.go index 9f7834b..8cf7858 100644 --- a/v3/example_test.go +++ b/v3/example_test.go @@ -293,3 +293,11 @@ func ExampleConfig_custommetrics() { circuit.NewCircuitFromConfig("custom-metrics", config) // Output: } + +// Shows how to check if an error is part of the circuit library. +func ExampleError_checking() { + x := errors.New("an error") + if _, ok := x.(circuit.Error); ok { + // this error is a circuit library error, not the result of runFunc or fallbackFunc + } +} diff --git a/v3/metrics/statsdmetrics/statsd.go b/v3/metrics/statsdmetrics/statsd.go index cf8d9c1..b3fdb20 100644 --- a/v3/metrics/statsdmetrics/statsd.go +++ b/v3/metrics/statsdmetrics/statsd.go @@ -90,9 +90,9 @@ type ConcurrencyCollector struct { Delay faststats.AtomicInt64 onClose chan struct{} Manager *circuit.Manager - SampleRate float32 timeAfter func(time.Duration) <-chan time.Time once sync.Once + SampleRate float32 } func (c *ConcurrencyCollector) delay() time.Duration { diff --git a/v3/metrics/statsdmetrics/statsd_test.go b/v3/metrics/statsdmetrics/statsd_test.go index 94e24ec..d656f43 100644 --- a/v3/metrics/statsdmetrics/statsd_test.go +++ b/v3/metrics/statsdmetrics/statsd_test.go @@ -147,6 +147,7 @@ func Test_sanitizeStatsd(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { if got := sanitizeStatsd(tt.args.s); got != tt.want { t.Errorf("sanitizeStatsd() = %v, want %v", got, tt.want) @@ -162,7 +163,7 @@ func TestConcurrencyCollector_delay(t *testing.T) { require.Equal(t, x.delay(), time.Second*3) } -func waitForGauge(name string, ss *rememberStats, clk *clock.MockClock) { +func waitForGauge(name string, ss *rememberStats, _ *clock.MockClock) { hasGauge := false for !hasGauge { time.Sleep(time.Millisecond) @@ -174,7 +175,7 @@ func waitForGauge(name string, ss *rememberStats, clk *clock.MockClock) { } } -func waitForCounter(name string, ss *rememberStats, clk *clock.MockClock) { +func waitForCounter(name string, ss *rememberStats, _ *clock.MockClock) { hasCounter := false for !hasCounter { time.Sleep(time.Millisecond) From 4d3f8440d1e32987329b3bca4f528a788b74d477 Mon Sep 17 00:00:00 2001 From: Jack Lindamood Date: Tue, 27 Aug 2019 10:23:08 -0700 Subject: [PATCH 2/2] errors: type check circuitError --- v3/errors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/v3/errors.go b/v3/errors.go index dfa95ce..712d5ce 100644 --- a/v3/errors.go +++ b/v3/errors.go @@ -11,6 +11,7 @@ type circuitError struct { circuitOpen bool msg string } +var _ Error = &circuitError{} // Error is the type of error returned by internal errors using the circuit library. type Error interface {