-
Notifications
You must be signed in to change notification settings - Fork 2
/
circuit.go
84 lines (76 loc) · 2.68 KB
/
circuit.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
package gobreak
import (
"sync"
"time"
"github.com/sony/gobreaker"
)
var (
// circuitBreaker holds a map filled with TwoStepCircuitBreaker
circuitBreaker map[string]*gobreaker.TwoStepCircuitBreaker
// circuitBreakerMutex is a RWMutex lock for circuitBreaker
circuitBreakerMutex *sync.RWMutex
)
func init() {
circuitBreaker = make(map[string]*gobreaker.TwoStepCircuitBreaker)
circuitBreakerMutex = &sync.RWMutex{}
}
// getCircuit returns a TwoStepCircuitBreaker by name
func getCircuit(name string) *gobreaker.TwoStepCircuitBreaker {
circuitBreakerMutex.RLock()
cb, ok := circuitBreaker[name]
if !ok {
circuitBreakerMutex.RUnlock()
circuitBreakerMutex.Lock()
defer circuitBreakerMutex.Unlock()
// because we released the rlock before we obtained the exclusive lock,
// we need to double check that some other thread didn't beat us to
// creation.
if cb, ok := circuitBreaker[name]; ok {
return cb
}
cb = newCircuitBreaker(name)
circuitBreaker[name] = cb
} else {
defer circuitBreakerMutex.RUnlock()
}
return cb
}
// newCircuitBreaker creates TwoStepCircuitBreaker with suitable settings.
//
// Name is the name of the CircuitBreaker.
//
// MaxRequests is the maximum number of requests allowed to pass through
// when the CircuitBreaker is half-open.
// If MaxRequests is 0, the CircuitBreaker allows only 1 request.
//
// Interval is the cyclic period of the closed state
// for the CircuitBreaker to clear the internal Counts.
// If Interval is 0, the CircuitBreaker doesn't clear internal Counts during the closed state.
//
// Timeout is the period of the open state,
// after which the state of the CircuitBreaker becomes half-open.
// If Timeout is 0, the timeout value of the CircuitBreaker is set to 60 seconds.
//
// ReadyToTrip is called with a copy of Counts whenever a request fails in the closed state.
// If ReadyToTrip returns true, the CircuitBreaker will be placed into the open state.
// If ReadyToTrip is nil, default ReadyToTrip is used.
//
// Default settings:
// MaxRequests: 3
// Interval: 5 * time.Second
// Timeout: 10 * time.Second
// ReadyToTrip: DefaultReadyToTrip
func newCircuitBreaker(name string) *gobreaker.TwoStepCircuitBreaker {
return gobreaker.NewTwoStepCircuitBreaker(gobreaker.Settings{
Name: name,
MaxRequests: 3,
Interval: 5 * time.Second,
Timeout: 10 * time.Second,
ReadyToTrip: DefaultReadyToTrip,
})
}
// DefaultReadyToTrip returns true when the number of consecutive failures is more than 3 and rate of failure is more than 60%.
func DefaultReadyToTrip(counts gobreaker.Counts) bool {
failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
return counts.ConsecutiveFailures >= 3 && failureRatio >= 0.6
}