1
- package rate // import "gopkg.in/go-redis/rate.v4"
1
+ package rate
2
2
3
3
import (
4
4
"fmt"
5
5
"time"
6
6
7
- timerate "golang.org/x/time/rate "
7
+ redis "gopkg.in/redis.v4 "
8
8
9
- "gopkg.in/redis.v4 "
9
+ timerate "golang.org/x/time/rate "
10
10
)
11
11
12
12
const redisPrefix = "rate"
@@ -15,38 +15,46 @@ type rediser interface {
15
15
Pipelined (func (pipe * redis.Pipeline ) error ) ([]redis.Cmder , error )
16
16
}
17
17
18
+ //Limiter type
18
19
type Limiter struct {
19
20
fallbackLimiter * timerate.Limiter
20
21
redis rediser
21
22
}
22
23
23
- // A Limiter controls how frequently events are allowed to happen. It uses
24
- // the redis to store data and fallbacks to the fallbackLimiter
25
- // when Redis Server is not available.
24
+ // NewLimiter creates a limiter that controls how frequently events
25
+ // are allowed to happen. It uses redis to store data and fallbacks
26
+ // to the fallbackLimiter when Redis Server is not available.
26
27
func NewLimiter (redis rediser , fallbackLimiter * timerate.Limiter ) * Limiter {
27
28
return & Limiter {
28
29
fallbackLimiter : fallbackLimiter ,
29
30
redis : redis ,
30
31
}
31
32
}
32
33
33
- // Allow reports whether an event with given name may happen at time now.
34
- // It allows up to maxn events within duration dur.
35
- func (l * Limiter ) Allow (name string , maxn int64 , dur time.Duration ) (count , reset int64 , allow bool ) {
34
+ // AllowN reports whether an event with given name may happen at time now.
35
+ // It allows up to maxn events within duration dur, with each interaction incrementing
36
+ // the limit by n.
37
+ func (l * Limiter ) AllowN (name string , maxn int64 , dur time.Duration , n int64 ) (count , reset int64 , allow bool ) {
36
38
udur := int64 (dur / time .Second )
37
39
slot := time .Now ().Unix () / udur
38
40
reset = (slot + 1 ) * udur
39
41
allow = l .fallbackLimiter .Allow ()
40
42
41
43
name = fmt .Sprintf ("%s:%s-%d" , redisPrefix , name , slot )
42
- count , err := l .incr (name , dur )
44
+ count , err := l .incr (name , dur , n )
43
45
if err == nil {
44
46
allow = count <= maxn
45
47
}
46
48
47
49
return count , reset , allow
48
50
}
49
51
52
+ // Allow reports whether an event with given name may happen at time now.
53
+ // It allows up to maxn events within duration dur.
54
+ func (l * Limiter ) Allow (name string , maxn int64 , dur time.Duration ) (count , reset int64 , allow bool ) {
55
+ return l .AllowN (name , maxn , dur , 1 )
56
+ }
57
+
50
58
// AllowMinute is shorthand for Allow(name, maxn, time.Minute).
51
59
func (l * Limiter ) AllowMinute (name string , maxn int64 ) (int64 , int64 , bool ) {
52
60
return l .Allow (name , maxn , time .Minute )
@@ -79,7 +87,7 @@ func (l *Limiter) AllowRate(name string, rateLimit timerate.Limit) (delay time.D
79
87
allow = l .fallbackLimiter .Allow ()
80
88
81
89
name = fmt .Sprintf ("%s:%s-%d-%d" , redisPrefix , name , dur , slot )
82
- count , err := l .incr (name , dur )
90
+ count , err := l .incr (name , dur , 1 )
83
91
if err == nil {
84
92
allow = count <= limit
85
93
}
@@ -91,10 +99,10 @@ func (l *Limiter) AllowRate(name string, rateLimit timerate.Limit) (delay time.D
91
99
return delay , allow
92
100
}
93
101
94
- func (l * Limiter ) incr (name string , dur time.Duration ) (int64 , error ) {
102
+ func (l * Limiter ) incr (name string , dur time.Duration , n int64 ) (int64 , error ) {
95
103
var incr * redis.IntCmd
96
104
_ , err := l .redis .Pipelined (func (pipe * redis.Pipeline ) error {
97
- incr = pipe .Incr (name )
105
+ incr = pipe .IncrBy (name , n )
98
106
pipe .Expire (name , dur )
99
107
return nil
100
108
})
0 commit comments