Implementation of the circuit breaker pattern in Go.
The circuit breaker can prevent an application from repeatedly trying to execute an operation that's likely to fail. It is implemented as a state machine with the following states:
Closed: the request from the application is allowed to pass.Half-Open: a limited number of requests are allowed to pass.Open: the request is failed immediately and an error returned.
funcNewBreaker(interval time.Duration, cooldown time.Duration, atLeastReqsuint32, toOpenToState, toClosedToState) (*Breaker, error)intervalis the cyclic period of the closed state.cooldownis the period of the open state,atLeastReqsis the number of requests to consider in the half-open state before invoking a given toClosed function for decision making.toOpenis called whenever a request fails in the closed state. If it returns true, the circuit breaker will be placed into the open state.toClosedis called in the half-open state once the number of requests reached atLeastReqs. If it returns true, the circuit breaker will be placed into the closed state, otherwise into the open state.
A function signature of toOpen and toClosed:
func(totaluint32, failuresuint32) boolExecute runs a given request if the circuit breaker accepts it,
cases when it's in the closed state, or half-open one
and the number of requests has not yet reached atLeastReqs.
Returns ErrBreakerOpen when it doesn't accept the request, otherwise the error from the req function:
func (b*Breaker) Execute(reqfunc() error) error// open the circuit breaker in case of 5% of failed requeststoOpen:=func(totaluint32, failuresuint32) bool {
returntotal>0&&float64(failures)/float64(total) >=0.05
}
// close the circuit breaker only if no failurestoClosed:=func(totaluint32, failuresuint32) bool {
returnfailures==0
}
b, err:=circuit.NewBreaker(time.Minute, 10*time.Second, 1, toOpen, toClosed)
iferr!=nil {
panic(err)
}
funcGetStatus(urlstring) (string, error) {
varresp*http.Responseerr=b.Execute(func() error {
resp, err=http.Get(url)
returnerr
})
iferr==circuit.ErrBreakerOpen {
// the circuit breaker failed fast,// there is still time for fallbackreturn"200 (cache)", nil
}
iferr!=nil {
// the request failedreturn"", err
}
returnresp.Status, nil
}