diff --git a/CHANGELOG.md b/CHANGELOG.md index 9977548..a821bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # Changelog All notable changes to this project will be documented in this file. +### 1.1.2 - 2014-08-20 + +### Added +- Nothing + +### Deprecated +- Nothing + +### Fixed +- For a FrequencyBreaker, Failures() should return the count since the duration start, even after resetting. + ## 1.1.1 - 2014-08-20 ### Added diff --git a/circuitbreaker.go b/circuitbreaker.go index cb7c731..a2bf938 100644 --- a/circuitbreaker.go +++ b/circuitbreaker.go @@ -213,7 +213,8 @@ type FrequencyBreaker struct { // Threshold is the number of failures Breaker will allow before tripping Threshold int64 - _failureTick unsafe.Pointer + _failureTick unsafe.Pointer + failuresSinceTick int64 *TrippableBreaker } @@ -221,7 +222,7 @@ type FrequencyBreaker struct { // and failure threshold. If a duration is specified as 0 then no duration will be used and // the behavior will be the same as a ThresholdBreaker func NewFrequencyBreaker(duration time.Duration, threshold int64) *FrequencyBreaker { - return &FrequencyBreaker{duration, threshold, nil, NewTrippableBreaker(time.Millisecond * 500)} + return &FrequencyBreaker{duration, threshold, nil, 0, NewTrippableBreaker(time.Millisecond * 500)} } // Fail records a failure. If the failure count meets the threshold within the duration, @@ -232,6 +233,7 @@ func (cb *FrequencyBreaker) Fail() { } cb.TrippableBreaker.Fail() + atomic.AddInt64(&cb.failuresSinceTick, 1) failures := atomic.AddInt64(&cb.failures, 1) if failures == cb.Threshold { cb.Trip() @@ -241,10 +243,15 @@ func (cb *FrequencyBreaker) Fail() { // Failures returns the number of failures for this circuit breaker. The failure count // for a FrequencyBreaker resets when the duration expires. func (cb *FrequencyBreaker) Failures() int64 { - if cb.Duration > 0 && (time.Since(cb.failureTick()) > cb.Duration) { + if cb.Duration <= 0 { + return cb.TrippableBreaker.Failures() + } + + if time.Since(cb.failureTick()) > cb.Duration { + atomic.StoreInt64(&cb.failuresSinceTick, 0) return 0 } - return cb.TrippableBreaker.Failures() + return atomic.LoadInt64(&cb.failuresSinceTick) } func (cb *FrequencyBreaker) frequencyFail() { diff --git a/circuitbreaker_test.go b/circuitbreaker_test.go index 436f3c8..c972d13 100644 --- a/circuitbreaker_test.go +++ b/circuitbreaker_test.go @@ -109,8 +109,8 @@ func TestThresholdBreaker(t *testing.T) { } cb.Reset() - if cb.failures != 0 { - t.Fatalf("expected reset to set failures to 0, got %d", cb.failures) + if failures := cb.Failures(); failures != 0 { + t.Fatalf("expected reset to set failures to 0, got %d", failures) } if cb.Tripped() { t.Fatal("expected threshold breaker to be open") @@ -227,6 +227,12 @@ func TestFrequencyBreakerFailures(t *testing.T) { if f := cb.Failures(); f != 1 { t.Fatalf("expected failure count of 1, got %d", f) } + + cb.Reset() + if f := cb.Failures(); f != 1 { + t.Fatalf("expected failure count of 1, got %d", f) + } + time.Sleep(time.Millisecond) if f := cb.Failures(); f != 0 { t.Fatalf("expected failures count to be 0, got %d", f)