Skip to content

Commit 87f829b

Browse files
authored
Merge pull request go-redis#18 from go-redis/fix/cleanup
Clenaup
2 parents b7ae80e + 7da5469 commit 87f829b

File tree

4 files changed

+75
-43
lines changed

4 files changed

+75
-43
lines changed

.travis.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ services:
55
- redis-server
66

77
go:
8-
- 1.7
9-
- 1.8
10-
- 1.9
8+
- 1.10.x
9+
- 1.11.x
10+
- 1.12.x
1111
- tip
1212

1313
matrix:
@@ -17,3 +17,4 @@ matrix:
1717
install:
1818
- go get github.com/go-redis/redis
1919
- go get golang.org/x/time/rate
20+
- go get github.com/gordonklaus/ineffassign

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
all:
22
go test ./...
33
go test ./... -short -race
4+
env GOOS=linux GOARCH=386 go test ./...
45
go vet
6+
ineffassign .

internal_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package redis_rate
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"golang.org/x/time/rate"
8+
)
9+
10+
var limitPeriodTests = []struct {
11+
rate rate.Limit
12+
limit int64
13+
period time.Duration
14+
}{
15+
{rate.Every(time.Millisecond), 1000, time.Second},
16+
{rate.Every(time.Second), 1, time.Second},
17+
{rate.Every(time.Hour / 5), 1, 12 * time.Minute},
18+
}
19+
20+
func TestLimitPeriod(t *testing.T) {
21+
for i, test := range limitPeriodTests {
22+
limit, period := limitPeriod(test.rate)
23+
if limit != test.limit {
24+
t.Fatalf("%d: got %d, wanted %d", i, limit, test.limit)
25+
}
26+
if period != test.period {
27+
t.Fatalf("%d: got %s, wanted %s", i, period, test.period)
28+
}
29+
}
30+
}

rate.go

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ func NewLimiter(redis rediser) *Limiter {
2929
}
3030
}
3131

32-
// Reset resets the rate limit for the name in the given rate limit window.
33-
func (l *Limiter) Reset(name string, dur time.Duration) error {
34-
udur := int64(dur / time.Second)
35-
slot := time.Now().Unix() / udur
32+
// Reset resets the rate limit for the name in the given rate limit period.
33+
func (l *Limiter) Reset(name string, period time.Duration) error {
34+
secs := int64(period / time.Second)
35+
slot := time.Now().Unix() / secs
3636

3737
name = allowName(name, slot)
3838
return l.redis.Del(name).Err()
3939
}
4040

41-
// Reset resets the rate limit for the name and limit.
41+
// ResetRate resets the rate limit for the name and limit.
4242
func (l *Limiter) ResetRate(name string, rateLimit rate.Limit) error {
4343
if rateLimit == 0 {
4444
return nil
@@ -47,45 +47,40 @@ func (l *Limiter) ResetRate(name string, rateLimit rate.Limit) error {
4747
return nil
4848
}
4949

50-
dur := time.Second
51-
limit := int64(rateLimit)
52-
if limit == 0 {
53-
limit = 1
54-
dur *= time.Duration(1 / rateLimit)
55-
}
56-
slot := time.Now().UnixNano() / dur.Nanoseconds()
50+
_, period := limitPeriod(rateLimit)
51+
slot := time.Now().UnixNano() / period.Nanoseconds()
5752

58-
name = allowRateName(name, dur, slot)
53+
name = allowRateName(name, period, slot)
5954
return l.redis.Del(name).Err()
6055
}
6156

6257
// AllowN reports whether an event with given name may happen at time now.
63-
// It allows up to maxn events within duration dur, with each interaction
58+
// It allows up to maxn events within period, with each interaction
6459
// incrementing the limit by n.
6560
func (l *Limiter) AllowN(
66-
name string, maxn int64, dur time.Duration, n int64,
61+
name string, maxn int64, period time.Duration, n int64,
6762
) (count int64, delay time.Duration, allow bool) {
68-
udur := int64(dur / time.Second)
63+
secs := int64(period / time.Second)
6964
utime := time.Now().Unix()
70-
slot := utime / udur
71-
delay = time.Duration((slot+1)*udur-utime) * time.Second
65+
slot := utime / secs
66+
delay = time.Duration((slot+1)*secs-utime) * time.Second
7267

7368
if l.Fallback != nil {
7469
allow = l.Fallback.Allow()
7570
}
7671

7772
name = allowName(name, slot)
78-
count, err := l.incr(name, dur, n)
73+
count, err := l.incr(name, period, n)
7974
if err == nil {
8075
allow = count <= maxn
8176
}
8277

8378
return count, delay, allow
8479
}
8580

86-
// Allow is shorthand for AllowN(name, max, dur, 1).
87-
func (l *Limiter) Allow(name string, maxn int64, dur time.Duration) (count int64, delay time.Duration, allow bool) {
88-
return l.AllowN(name, maxn, dur, 1)
81+
// Allow is shorthand for AllowN(name, max, period, 1).
82+
func (l *Limiter) Allow(name string, maxn int64, period time.Duration) (count int64, delay time.Duration, allow bool) {
83+
return l.AllowN(name, maxn, period, 1)
8984
}
9085

9186
// AllowMinute is shorthand for Allow(name, maxn, time.Minute).
@@ -108,37 +103,41 @@ func (l *Limiter) AllowRate(name string, rateLimit rate.Limit) (delay time.Durat
108103
return 0, true
109104
}
110105

111-
dur := time.Second
112-
limit := int64(rateLimit)
113-
if limit == 0 {
114-
limit = 1
115-
dur *= time.Duration(1 / rateLimit)
116-
}
106+
limit, period := limitPeriod(rateLimit)
117107
now := time.Now()
118-
slot := now.UnixNano() / dur.Nanoseconds()
108+
slot := now.UnixNano() / period.Nanoseconds()
119109

120-
if l.Fallback != nil {
121-
allow = l.Fallback.Allow()
122-
}
123-
124-
name = allowRateName(name, dur, slot)
125-
count, err := l.incr(name, dur, 1)
110+
name = allowRateName(name, period, slot)
111+
count, err := l.incr(name, period, 1)
126112
if err == nil {
127113
allow = count <= limit
114+
} else if l.Fallback != nil {
115+
allow = l.Fallback.Allow()
128116
}
129117

130118
if !allow {
131-
delay = time.Duration(slot+1)*dur - time.Duration(now.UnixNano())
119+
delay = time.Duration(slot+1)*period - time.Duration(now.UnixNano())
132120
}
133121

134122
return delay, allow
135123
}
136124

137-
func (l *Limiter) incr(name string, dur time.Duration, n int64) (int64, error) {
125+
func limitPeriod(rl rate.Limit) (limit int64, period time.Duration) {
126+
period = time.Second
127+
if rl < 1 {
128+
limit = 1
129+
period *= time.Duration(1 / rl)
130+
} else {
131+
limit = int64(rl)
132+
}
133+
return limit, period
134+
}
135+
136+
func (l *Limiter) incr(name string, period time.Duration, n int64) (int64, error) {
138137
var incr *redis.IntCmd
139138
_, err := l.redis.Pipelined(func(pipe redis.Pipeliner) error {
140139
incr = pipe.IncrBy(name, n)
141-
pipe.Expire(name, dur)
140+
pipe.Expire(name, period+30*time.Second)
142141
return nil
143142
})
144143

@@ -150,6 +149,6 @@ func allowName(name string, slot int64) string {
150149
return fmt.Sprintf("%s:%s-%d", redisPrefix, name, slot)
151150
}
152151

153-
func allowRateName(name string, dur time.Duration, slot int64) string {
154-
return fmt.Sprintf("%s:%s-%d-%d", redisPrefix, name, dur, slot)
152+
func allowRateName(name string, period time.Duration, slot int64) string {
153+
return fmt.Sprintf("%s:%s-%d-%d", redisPrefix, name, period, slot)
155154
}

0 commit comments

Comments
 (0)