-
Notifications
You must be signed in to change notification settings - Fork 6
/
api.go
100 lines (87 loc) · 2.39 KB
/
api.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
package goBreaker
import (
"log"
"sync"
"time"
)
const (
// MinQps determines the MinSamples when using AdjustBreakers func
DEFAULT_BREAKER_MINQPS = 200
)
type CircuitBreaker struct {
Breakers map[int32]*Breaker
Mutex sync.RWMutex
}
var BreakerWhitelist = map[int32]bool{}
func InitCircuitBreakers(cmds []int32, options Options) (cb CircuitBreaker) {
cb.Breakers = map[int32]*Breaker{}
for _, cmd := range cmds {
cb.Breakers[cmd] = cb.GenBreaker(cmd, options)
}
return cb
}
func (b *CircuitBreaker) GetBreaker(cmd int32) *Breaker {
b.Mutex.RLock()
defer b.Mutex.RUnlock()
cb := b.Breakers[cmd]
if cb == nil {
return b.GenBreaker(cmd, Options{})
}
return cb
}
func (b *CircuitBreaker) GetAllBreakers() map[int32]*Breaker {
breakers := map[int32]*Breaker{}
b.Mutex.RLock()
defer b.Mutex.RUnlock()
for cmd, breaker := range b.Breakers {
breakers[cmd] = breaker
}
return breakers
}
// when instances >1, you can use AdjustBreakers
//count means how many instances you have
func (b *CircuitBreaker) AdjustBreakers(count int, options Options) {
var preCount, breakerWindows int
windowTime := options.BucketTime * time.Duration(options.BucketNums)
breakerWindows = int(windowTime / 1000000000)
if options.BreakerMinQPS <= 0 {
options.BreakerMinQPS = DEFAULT_BREAKER_MINQPS
}
for {
if count == preCount {
time.Sleep(time.Minute)
continue
}
preCount = count
options.BreakerMinSamples = breakerWindows * options.BreakerMinQPS / count
log.Printf("breaker min sample change, instances count: %v, sample: %v", count, options.BreakerMinSamples)
b.Mutex.Lock()
for cmd := range b.Breakers {
b.Breakers[cmd] = b.GenBreaker(cmd, options)
}
b.Mutex.Unlock()
time.Sleep(time.Minute)
}
}
func (b *CircuitBreaker) GenBreaker(cmd int32, options Options) *Breaker {
callback := func(oldState, newState State, m Container) {
log.Printf("breaker state change, command %v: %s -> %s, (succ: %d, err: %d, timeout: %d, rate: %.2f)",
cmd, oldState.String(), newState.String(),
m.Successes(), m.Failures(), m.Timeouts(), m.ErrorRate())
}
if options.StateChangeHandler == nil {
options.StateChangeHandler = callback
}
defaultBreaker, _ := NewBreaker(options)
return defaultBreaker
}
func (b *CircuitBreaker) IsTriggerBreaker(cmd int32) bool {
if BreakerWhitelist[cmd] {
return false
}
breaker := b.GetBreaker(cmd)
if !breaker.IsAllowed() {
return true
}
return false
}