-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathlimiter.go
63 lines (56 loc) · 1.07 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
60
61
62
63
package dsc
import (
"sync"
"sync/atomic"
"time"
)
type timeWindow struct {
Start time.Time
End time.Time
}
//Limiter represents resource limter
type Limiter struct {
count int64
max int
duration time.Duration
win *timeWindow
mux *sync.Mutex
}
//Acquire checks if limit for current time window was not exhausted or sleep
func (l *Limiter) Acquire() {
for {
window := l.window()
if int(atomic.AddInt64(&l.count, 1)) <= l.max {
return
}
duration := window.End.Sub(time.Now())
if duration > 0 {
time.Sleep(duration)
}
}
}
func (l *Limiter) window() *timeWindow {
l.mux.Lock()
defer l.mux.Unlock()
if time.Now().After(l.win.End) {
l.win.Start = time.Now()
l.win.End = time.Now().Add(l.duration)
atomic.StoreInt64(&l.count, 0)
}
return l.win
}
//NewLimiter creates a new limiter
func NewLimiter(duration time.Duration, max int) *Limiter {
if max == 0 {
max = 1
}
return &Limiter{
mux: &sync.Mutex{},
duration: duration,
win: &timeWindow{
Start: time.Now(),
End: time.Now().Add(duration),
},
max: max,
}
}