Skip to content

Commit 5ea37e7

Browse files
committed
All old expressed in terms of new
1 parent 9715034 commit 5ea37e7

File tree

2 files changed

+36
-61
lines changed

2 files changed

+36
-61
lines changed

ratelimit/token_bucket.go

+5-10
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,11 @@ func NewTokenBucketLimiter(tb *ratelimit.Bucket) endpoint.Middleware {
2323

2424
// NewTokenBucketThrottler returns an endpoint.Middleware that acts as a
2525
// request throttler based on a token-bucket algorithm. Requests that would
26-
// exceed the maximum request rate are delayed via the parameterized sleep
27-
// function. By default you may pass time.Sleep.
28-
func NewTokenBucketThrottler(tb *ratelimit.Bucket, sleep func(time.Duration)) endpoint.Middleware {
29-
// return NewDelayingLimiter(NewWaiter(tb))
30-
return func(next endpoint.Endpoint) endpoint.Endpoint {
31-
return func(ctx context.Context, request interface{}) (interface{}, error) {
32-
sleep(tb.Take(1))
33-
return next(ctx, request)
34-
}
35-
}
26+
// exceed the maximum request rate are delayed.
27+
// The parameterized function "_" is kept for backwards-compatiblity of
28+
// the API, but it is no longer used for anything. You may pass it nil.
29+
func NewTokenBucketThrottler(tb *ratelimit.Bucket, _ func(time.Duration)) endpoint.Middleware {
30+
return NewDelayingLimiter(NewWaiter(tb))
3631
}
3732

3833
// Allower dictates whether or not a request is acceptable to run.

ratelimit/token_bucket_test.go

+31-51
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,62 @@ package ratelimit_test
22

33
import (
44
"context"
5-
"math"
65
"strings"
76
"testing"
87
"time"
98

109
jujuratelimit "github.com/juju/ratelimit"
10+
"golang.org/x/time/rate"
1111

1212
"github.com/go-kit/kit/endpoint"
1313
"github.com/go-kit/kit/ratelimit"
14-
"golang.org/x/time/rate"
1514
)
1615

16+
var nopEndpoint = func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
17+
1718
func TestTokenBucketLimiter(t *testing.T) {
18-
e := func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
19-
for _, n := range []int{1, 2, 100} {
20-
tb := jujuratelimit.NewBucketWithRate(float64(n), int64(n))
21-
testLimiter(t, ratelimit.NewTokenBucketLimiter(tb)(e), n)
22-
}
19+
tb := jujuratelimit.NewBucket(time.Minute, 1)
20+
testSuccessThenFailure(
21+
t,
22+
ratelimit.NewTokenBucketLimiter(tb)(nopEndpoint),
23+
ratelimit.ErrLimited.Error())
2324
}
2425

2526
func TestTokenBucketThrottler(t *testing.T) {
26-
d := time.Duration(0)
27-
s := func(d0 time.Duration) { d = d0 }
28-
29-
e := func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
30-
e = ratelimit.NewTokenBucketThrottler(jujuratelimit.NewBucketWithRate(1, 1), s)(e)
31-
32-
// First request should go through with no delay.
33-
e(context.Background(), struct{}{})
34-
if want, have := time.Duration(0), d; want != have {
35-
t.Errorf("want %s, have %s", want, have)
36-
}
37-
38-
// Next request should request a ~1s sleep.
39-
e(context.Background(), struct{}{})
40-
if want, have, tol := time.Second, d, time.Millisecond; math.Abs(float64(want-have)) > float64(tol) {
41-
t.Errorf("want %s, have %s", want, have)
42-
}
43-
}
44-
45-
func testLimiter(t *testing.T, e endpoint.Endpoint, rate int) {
46-
// First <rate> requests should succeed.
47-
for i := 0; i < rate; i++ {
48-
if _, err := e(context.Background(), struct{}{}); err != nil {
49-
t.Fatalf("rate=%d: request %d/%d failed: %v", rate, i+1, rate, err)
50-
}
51-
}
52-
53-
// Next request should fail.
54-
if _, err := e(context.Background(), struct{}{}); err != ratelimit.ErrLimited {
55-
t.Errorf("rate=%d: want %v, have %v", rate, ratelimit.ErrLimited, err)
56-
}
27+
tb := jujuratelimit.NewBucket(time.Minute, 1)
28+
testSuccessThenFailure(
29+
t,
30+
ratelimit.NewTokenBucketThrottler(tb, nil)(nopEndpoint),
31+
"context deadline exceeded")
5732
}
5833

5934
func TestXRateErroring(t *testing.T) {
6035
limit := rate.NewLimiter(rate.Every(time.Minute), 1)
61-
e := func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
62-
testLimiter(t, ratelimit.NewErroringLimiter(limit)(e), 1)
36+
testSuccessThenFailure(
37+
t,
38+
ratelimit.NewErroringLimiter(limit)(nopEndpoint),
39+
ratelimit.ErrLimited.Error())
6340
}
6441

6542
func TestXRateDelaying(t *testing.T) {
6643
limit := rate.NewLimiter(rate.Every(time.Minute), 1)
67-
e := func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
68-
e = ratelimit.NewDelayingLimiter(limit)(e)
44+
testSuccessThenFailure(
45+
t,
46+
ratelimit.NewDelayingLimiter(limit)(nopEndpoint),
47+
"exceed context deadline")
48+
}
6949

70-
_, err := e(context.Background(), struct{}{})
71-
if err != nil {
50+
func testSuccessThenFailure(t *testing.T, e endpoint.Endpoint, failContains string) {
51+
ctx, cxl := context.WithTimeout(context.Background(), 500*time.Millisecond)
52+
defer cxl()
53+
54+
// First request should succeed.
55+
if _, err := e(ctx, struct{}{}); err != nil {
7256
t.Errorf("unexpected: %v\n", err)
7357
}
7458

75-
dur := 500 * time.Millisecond
76-
ctx, cxl := context.WithTimeout(context.Background(), dur)
77-
defer cxl()
78-
79-
_, err = e(ctx, struct{}{})
80-
if !strings.Contains(err.Error(), "exceed context deadline") {
81-
t.Errorf("expected timeout: %v\n", err)
59+
// Next request should fail.
60+
if _, err := e(ctx, struct{}{}); !strings.Contains(err.Error(), failContains) {
61+
t.Errorf("expected `%s`: %v\n", failContains, err)
8262
}
8363
}

0 commit comments

Comments
 (0)