-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathlimiter.go
59 lines (46 loc) · 1.16 KB
/
limiter.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
59
package iocontrol
import (
"sync/atomic"
"time"
"github.com/benbjohnson/clock"
)
type rateLimiter struct {
limitPerSec int
resolution time.Duration
time clock.Clock // YAGNI wrapper for YAGNI deterministic testing
batchDone int64
lastBatch time.Time
// can be modified concurrently
maxPerBatch int64
}
func newRateLimiter(perSec int, maxBurst time.Duration) *rateLimiter {
maxPerBatch := int64(perSec / int(time.Second/maxBurst))
return &rateLimiter{
limitPerSec: perSec,
resolution: maxBurst,
time: clock.New(),
maxPerBatch: maxPerBatch,
}
}
func (r *rateLimiter) CanDo() (canDo int) {
perBatch := atomic.LoadInt64(&r.maxPerBatch)
canDo = int(perBatch - r.batchDone)
if canDo < 0 {
return 0
}
return canDo
}
func (r *rateLimiter) Did(n int) {
r.batchDone += int64(n)
}
func (r *rateLimiter) SetRate(perSec int) {
maxPerBatch := int64(perSec / int(time.Second/r.resolution))
atomic.StoreInt64(&r.maxPerBatch, maxPerBatch)
}
func (r *rateLimiter) Limit() {
nextBatch := r.lastBatch.Add(r.resolution)
durationToNextBatch := nextBatch.Sub(r.time.Now())
r.time.Sleep(durationToNextBatch)
r.lastBatch = r.time.Now()
r.batchDone = 0
}