2017-03-31 18:01:58 +02:00
|
|
|
package ratelimit
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/juju/ratelimit"
|
2017-05-18 18:54:23 +02:00
|
|
|
"golang.org/x/net/context"
|
2017-03-31 18:01:58 +02:00
|
|
|
|
|
|
|
"github.com/go-kit/kit/endpoint"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ErrLimited is returned in the request path when the rate limiter is
|
|
|
|
// triggered and the request is rejected.
|
|
|
|
var ErrLimited = errors.New("rate limit exceeded")
|
|
|
|
|
|
|
|
// NewTokenBucketLimiter returns an endpoint.Middleware that acts as a rate
|
|
|
|
// limiter based on a token-bucket algorithm. Requests that would exceed the
|
|
|
|
// maximum request rate are simply rejected with an error.
|
|
|
|
func NewTokenBucketLimiter(tb *ratelimit.Bucket) endpoint.Middleware {
|
|
|
|
return func(next endpoint.Endpoint) endpoint.Endpoint {
|
|
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
|
|
if tb.TakeAvailable(1) == 0 {
|
|
|
|
return nil, ErrLimited
|
|
|
|
}
|
|
|
|
return next(ctx, request)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewTokenBucketThrottler returns an endpoint.Middleware that acts as a
|
|
|
|
// request throttler based on a token-bucket algorithm. Requests that would
|
|
|
|
// exceed the maximum request rate are delayed via the parameterized sleep
|
|
|
|
// function. By default you may pass time.Sleep.
|
|
|
|
func NewTokenBucketThrottler(tb *ratelimit.Bucket, sleep func(time.Duration)) endpoint.Middleware {
|
|
|
|
return func(next endpoint.Endpoint) endpoint.Endpoint {
|
|
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
|
|
sleep(tb.Take(1))
|
|
|
|
return next(ctx, request)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|