Skip to content

Instantly share code, notes, and snippets.

@danielfbm
Last active October 26, 2022 06:25
Show Gist options
  • Save danielfbm/bcf036ba6a94caa160e4d749a3a9c6fe to your computer and use it in GitHub Desktop.
Save danielfbm/bcf036ba6a94caa160e4d749a3a9c6fe to your computer and use it in GitHub Desktop.
package main
import (
"time"
redis "gopkg.in/redis.v5"
)
// CircuitBreaker responsible for creating a circuit breaking
// logic for redis client
type CircuitBreaker struct {
// backoff time before retrying
Backoff time.Duration
// max number of retries before backoff
MaxRetries int
// backoff internals
isBackoff bool
retries int
backoffStart time.Time
}
func (c *CircuitBreaker) handleError(err error) error {
if err == nil {
if c.isBackoff {
c.reset()
}
return nil
}
c.retries++
if c.retries > c.MaxRetries {
c.isBackoff = true
c.backoffStart = time.Now()
}
return err
}
// IsBackoff returns true if the circuit braker is locked
func (c *CircuitBreaker) IsBackoff() bool {
if !c.isBackoff {
return false
}
if c.backoffStart.Add(c.Backoff).Before(time.Now()) {
// should unlock
c.reset()
}
return c.isBackoff
}
func (c *CircuitBreaker) reset() {
c.isBackoff = false
c.retries = 0
c.backoffStart = time.Time{}
}
// KeyIncrFunc key function definition
type KeyIncrFunc func(key string) *redis.IntCmd
func (c *CircuitBreaker) KeyFunc(f KeyIncrFunc) KeyIncrFunc {
return func(key string) *redis.IntCmd {
if c.IsBackoff() {
return redis.NewIntCmd(key)
}
e := f(key)
c.handleError(e.Err())
return e
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment