// DefaultCircuitBreakerConfig creates a circuit breaker config usign the // default values for timeouts and half-closed retry probability, a constant // retry backoff of 1000ms, an any-error failure interpreter, and a trip // condition which fires only after five ocnsecutive failures. func DefaultCircuitBreakerConfig() *CircuitBreakerConfig { return &CircuitBreakerConfig{ InvocationTimeout: DefaultInvocationTimeout, HalfClosedRetryProbability: DefaultHalfClosedRetryProbability, ResetBackoff: backoff.NewConstantBackoff(1000 * time.Millisecond), FailureInterpreter: NewAnyErrorFailureInterpreter(), TripCondition: NewConsecutiveFailureTripCondition(5), } }
func (s *OvercurrentSuite) TestTimeoutDisabled(c *C) { cb := NewCircuitBreaker(&CircuitBreakerConfig{ InvocationTimeout: 0, ResetBackoff: backoff.NewConstantBackoff(250 * time.Millisecond), HalfClosedRetryProbability: 1, FailureInterpreter: NewAnyErrorFailureInterpreter(), TripCondition: NewConsecutiveFailureTripCondition(5), }) fn := func() error { <-time.After(250 * time.Millisecond) return nil } c.Assert(cb.Call(fn), Equals, nil) }
func (s *OvercurrentSuite) TestHalfOpenReset(c *C) { cb := NewCircuitBreaker(&CircuitBreakerConfig{ InvocationTimeout: DefaultInvocationTimeout, ResetBackoff: backoff.NewConstantBackoff(250 * time.Millisecond), HalfClosedRetryProbability: 1, FailureInterpreter: NewAnyErrorFailureInterpreter(), TripCondition: NewConsecutiveFailureTripCondition(5), }) err := errors.New("Test error.") fn1 := func() error { return err } fn2 := func() error { return nil } for i := 0; i < 5; i++ { c.Assert(cb.Call(fn1), Equals, err) } c.Assert(cb.Call(fn1), Equals, ErrCircuitOpen) <-time.After(250 * time.Millisecond) c.Assert(cb.Call(fn2), Equals, nil) }
func (s *OvercurrentSuite) TestHardTrip(c *C) { cb := NewCircuitBreaker(&CircuitBreakerConfig{ InvocationTimeout: DefaultInvocationTimeout, ResetBackoff: backoff.NewConstantBackoff(250 * time.Millisecond), HalfClosedRetryProbability: 1, FailureInterpreter: NewAnyErrorFailureInterpreter(), TripCondition: NewConsecutiveFailureTripCondition(1), }) fn := func() error { return nil } c.Assert(cb.Call(fn), Equals, nil) cb.Trip() c.Assert(cb.Call(fn), Equals, ErrCircuitOpen) <-time.After(250 * time.Millisecond) c.Assert(cb.Call(fn), Equals, ErrCircuitOpen) cb.Reset() c.Assert(cb.Call(fn), Equals, nil) }
func (s *OvercurrentSuite) TestHalfOpenProbability(c *C) { runs := 5000 prob := .25 dist := .01 success := 0 failure := 0 fn1 := func() error { return errors.New("Test error.") } fn2 := func() error { success++ return nil } for i := 0; i < runs; i++ { cb := NewCircuitBreaker(&CircuitBreakerConfig{ InvocationTimeout: DefaultInvocationTimeout, ResetBackoff: backoff.NewConstantBackoff(1 * time.Nanosecond), HalfClosedRetryProbability: prob, FailureInterpreter: NewAnyErrorFailureInterpreter(), TripCondition: NewConsecutiveFailureTripCondition(1), }) cb.Call(fn1) <-time.After(1 * time.Nanosecond) if cb.Call(fn2) == ErrCircuitOpen { failure++ } } lower := int(float64(runs)*prob - float64(runs)*dist) upper := int(float64(runs)*prob + float64(runs)*dist) c.Assert(success+failure, Equals, runs) c.Assert(lower <= success && success <= upper, Equals, true) }