-
Notifications
You must be signed in to change notification settings - Fork 0
/
rate.go
58 lines (49 loc) · 1.16 KB
/
rate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package ctxroutines
import (
"context"
"time"
"golang.org/x/time/rate"
)
// RatelimitRunner creates a Runner that respects the rate limit.
//
// Say you have an empty Runner r with rate limit to once per second:
//
// go r.Run() // returns immediatly
// go r.Run() // returns after a second
//
// Once the Runner has been canceled, Run() always return context.Canceled.
//
// RatelimitRunner() looks like RunAtLeast,
func RatelimitRunner(l *rate.Limiter, r Runner) (ret Runner) {
return &ratelimitRunner{
lim: l,
Runner: r,
}
}
// NoLessThan is a wrapper of RatelimitRunner
func NoLessThan(dur time.Duration, f Runner) Runner {
return RatelimitRunner(rate.NewLimiter(rate.Every(dur), 1), f)
}
type ratelimitRunner struct {
lim *rate.Limiter
Runner
}
func (r *ratelimitRunner) sleep(timeout time.Duration) (canceled bool) {
select {
case <-r.Context().Done():
return true
case <-time.After(timeout):
return false
}
}
func (r *ratelimitRunner) Run() (err error) {
if IsCanceled(r) {
return context.Canceled
}
reserve := r.lim.Reserve()
if r.sleep(reserve.Delay()) {
reserve.Cancel()
return context.Canceled
}
return r.Runner.Run()
}