Update circuit-breaker.md

This commit is contained in:
Edward 2020-05-22 14:16:24 +08:00 committed by GitHub
parent ac6bb97b58
commit 33e5b0d51a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -60,45 +60,52 @@ import (
"time" "time"
) )
type State int
const (
UnknownState State = iota
FailureState
SuccessState
)
type Counter interface {
Count(State)
ConsecutiveFailures() uint32
LastActivity() time.Time
Reset()
}
type Circuit func(context.Context) error type Circuit func(context.Context) error
var canRetry = func(cnt counters, failureThreshold uint32) bool {
backoffLevel := cnt.ConsecutiveFailures - failureThreshold
// Calculates when should the circuit breaker resume propagating requests
// to the service
shouldRetryAt := cnt.LastActivity().Add(time.Second << backoffLevel)
return time.Now().After(shouldRetryAt)
}
func Breaker(c Circuit, failureThreshold uint32) Circuit { func Breaker(c Circuit, failureThreshold uint32) Circuit {
cnt := NewCounter() cnt := counters{}
expired := time.Now()
currentState := StateClosed
return func(ctx context.Context) error {
//ctx can be used hold parameters
return func(ctx context.Context) error {
//handle statue transformation for timeout if cnt.ConsecutiveFailures >= failureThreshold {
if currentState == StateOpen { if !canRetry(cnt, failureThreshold) {
nowt := time.Now() // Fails fast instead of propagating requests to the circuit since
if expired.Before(nowt) || expired.Equal(nowt) { // not enough time has passed since the last failure to retry
currentState = StateHalfOpen return ErrServiceUnavailable
cnt.ConsecutiveSuccesses = 0
} }
} }
// Unless the failure threshold is exceeded the wrapped service mimics the
switch currentState { // old behavior and the difference in behavior is seen after consecutive failures
case StateOpen: if err := c(ctx); err != nil {
return ErrServiceUnavailable cnt.Count(FailureState)
case StateHalfOpen: return err
if err := c(ctx); err != nil {
currentState = StateOpen
expired = time.Now().Add(defaultTimeout) //Reset
return err
}
cnt.Count(SuccessState)
if cnt.ConsecutiveSuccesses > defaultSuccessThreshold {
currentState = StateClosed
cnt.ConsecutiveFailures = 0
}
case StateClosed:
if err := c(ctx); err != nil {
cnt.Count(FailureState)
}
} }
cnt.Count(SuccessState)
return nil return nil
} }
} }