Switch token bucket rate limiter to github.com/juju/ratelimit

This commit is contained in:
Jordan Liggitt
2015-06-30 09:59:37 -04:00
parent 800303c843
commit f265d5c5ee
2 changed files with 13 additions and 81 deletions

View File

@@ -16,10 +16,7 @@ limitations under the License.
package util
import (
"sync"
"time"
)
import "github.com/juju/ratelimit"
type RateLimiter interface {
// CanAccept returns true if the rate is below the limit, false otherwise
@@ -31,24 +28,17 @@ type RateLimiter interface {
}
type tickRateLimiter struct {
lock sync.Mutex
tokens chan bool
ticker <-chan time.Time
stop chan bool
limiter *ratelimit.Bucket
}
// NewTokenBucketRateLimiter creates a rate limiter which implements a token bucket approach.
// The rate limiter allows bursts of up to 'burst' to exceed the QPS, while still maintaining a
// smoothed qps rate of 'qps'.
// The bucket is initially filled with 'burst' tokens, the rate limiter spawns a go routine
// which refills the bucket with one token at a rate of 'qps'. The maximum number of tokens in
// the bucket is capped at 'burst'.
// When done with the limiter, Stop() must be called to halt the associated goroutine.
// The bucket is initially filled with 'burst' tokens, and refills at a rate of 'qps'.
// The maximum number of tokens in the bucket is capped at 'burst'.
func NewTokenBucketRateLimiter(qps float32, burst int) RateLimiter {
ticker := time.Tick(time.Duration(float32(time.Second) / qps))
rate := newTokenBucketRateLimiterFromTicker(ticker, burst)
go rate.run()
return rate
limiter := ratelimit.NewBucketWithRate(float64(qps), int64(burst))
return &tickRateLimiter{limiter}
}
type fakeRateLimiter struct{}
@@ -57,63 +47,16 @@ func NewFakeRateLimiter() RateLimiter {
return &fakeRateLimiter{}
}
func newTokenBucketRateLimiterFromTicker(ticker <-chan time.Time, burst int) *tickRateLimiter {
if burst < 1 {
panic("burst must be a positive integer")
}
rate := &tickRateLimiter{
tokens: make(chan bool, burst),
ticker: ticker,
stop: make(chan bool),
}
for i := 0; i < burst; i++ {
rate.tokens <- true
}
return rate
}
func (t *tickRateLimiter) CanAccept() bool {
select {
case <-t.tokens:
return true
default:
return false
}
return t.limiter.TakeAvailable(1) == 1
}
// Accept will block until a token becomes available
func (t *tickRateLimiter) Accept() {
<-t.tokens
t.limiter.Wait(1)
}
func (t *tickRateLimiter) Stop() {
close(t.stop)
}
func (r *tickRateLimiter) run() {
for {
if !r.step() {
break
}
}
}
func (r *tickRateLimiter) step() bool {
select {
case <-r.ticker:
r.increment()
return true
case <-r.stop:
return false
}
}
func (t *tickRateLimiter) increment() {
// non-blocking send
select {
case t.tokens <- true:
default:
}
}
func (t *fakeRateLimiter) CanAccept() bool {