-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhotstreak.go
150 lines (138 loc) · 2.87 KB
/
hotstreak.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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package hotstreak
import (
"sync"
"time"
)
// Hotstreak is the main structure of the library
type Hotstreak struct {
active bool
hot bool
mux *sync.Mutex
counter int
config Config
notifier chan uint8
}
// Config is the structure of the configuration that can be injected to the lib
type Config struct {
Limit int // Describes how many times we have to hit before a streak becomes hot
HotWait time.Duration // Describes the amount of time we are waiting before declaring a cool down
ActiveWait time.Duration // Describes the amount of time we are waiting to check on a streak being active
AlwaysActive bool // Describes if the streak can deactivate or not
}
var (
// DEACTIVATED - Status sign for the streak getting deactivated
DEACTIVATED uint8
// ACTIVATED - Status sign for the streak getting activated
ACTIVATED uint8 = 1
)
// New creates a new instance of Hotstreak
func New(config Config) *Hotstreak {
limit := config.Limit
if limit == 0 {
limit = 20
}
hotwait := config.HotWait
if hotwait == 0 {
hotwait = time.Minute * 5
}
activeWait := config.ActiveWait
if activeWait == 0 {
activeWait = time.Minute * 5
}
return &Hotstreak{
config: Config{
Limit: limit,
HotWait: hotwait,
ActiveWait: activeWait,
AlwaysActive: config.AlwaysActive,
},
mux: &sync.Mutex{},
notifier: make(chan uint8)}
}
func (hs *Hotstreak) coolDown() {
if hs == nil {
return
}
time.Sleep(hs.config.HotWait)
hs.mux.Lock()
defer hs.mux.Unlock()
hs.hot = false
hs.counter = 0
}
func (hs *Hotstreak) dieSlowly() {
if hs == nil {
return
}
select {
case <-hs.notifier:
return
case <-time.After(hs.config.ActiveWait):
if hs.config.AlwaysActive {
return
}
hs.mux.Lock()
defer hs.mux.Unlock()
if hs.hot || hs.counter > 0 {
go hs.dieSlowly()
hs.counter = 0
return
}
hs.active = false
}
}
// Hit is to ping the service increasing it's hotness
func (hs *Hotstreak) Hit() *Hotstreak {
if hs == nil {
return nil
}
hs.mux.Lock()
defer hs.mux.Unlock()
if hs.hot {
return hs
}
hs.counter++
if hs.counter >= hs.config.Limit {
hs.hot = true
go hs.coolDown()
}
return hs
}
// Activate turns on the streak
func (hs *Hotstreak) Activate() *Hotstreak {
if hs == nil {
return nil
}
if hs.active {
hs.notifier <- ACTIVATED
}
hs.active = true
go hs.dieSlowly()
return hs
}
// Deactivate turns off the streak
func (hs *Hotstreak) Deactivate() *Hotstreak {
if hs == nil {
return nil
}
if hs.active {
hs.notifier <- 0
}
hs.active = false
hs.hot = false
hs.counter = 0
return hs
}
// IsHot is for getting the hot status of Hotstreak
func (hs *Hotstreak) IsHot() bool {
if hs == nil {
return false
}
return hs.hot
}
// IsActive is for getting if the streak is active at all or not
func (hs *Hotstreak) IsActive() bool {
if hs == nil {
return false
}
return hs.active
}