Introduce cooldown period in rate limiter
@@ -4,6 +4,7 @@ import (
"net/http"
"strconv"
"sync"
+ "time"
"github.com/go-kit/kit/log"
"github.com/pkg/errors"
@@ -14,6 +15,7 @@ const (
minLimit = 0.1
backOffBy = 2.0
recoverBy = 1.5
+ coolDownInSeconds = 1200
)
// RateLimiters keeps track of per-host rate limiting for an arbitrary
@@ -33,6 +35,7 @@ type RateLimiters struct {
Burst int
Logger log.Logger
perHost map[string]*rate.Limiter
+ latestBackOffPerHost map[string]time.Time
mu sync.Mutex
}
@@ -70,7 +73,12 @@ func (limiters *RateLimiters) backOff(host string) {
if oldLimit != newLimit && limiters.Logger != nil {
limiters.Logger.Log("info", "reducing rate limit", "host", host, "limit", strconv.FormatFloat(newLimit, 'f', 2, 64))
}
- limiter.SetLimit(rate.Limit(newLimit))
+ backOffTime := time.Now()
+ limiter.SetLimitAt(backOffTime, rate.Limit(newLimit))
+ if limiters.latestBackOffPerHost == nil {
+ limiters.latestBackOffPerHost = map[string]time.Time{}
+ }
+ limiters.latestBackOffPerHost[host] = backOffTime
}
// Recover should be called when a use of a RoundTripper has
@@ -81,6 +89,11 @@ func (limiters *RateLimiters) Recover(host string) {
if limiters.perHost == nil {
return
}
+ if limiters.latestBackOffPerHost != nil {
+ if t, ok := limiters.latestBackOffPerHost[host]; ok && time.Since(t) < coolDownInSeconds*time.Second {
+ return
+ }
+ }
if limiter, ok := limiters.perHost[host]; ok {
oldLimit := float64(limiter.Limit())
newLimit := limiters.clip(oldLimit * recoverBy)
