Repository navigation
Expand file tree
/
Copy pathmanager.go
More file actions
114 lines (103 loc) · 3.67 KB
/
Copy pathmanager.go
File metadata and controls
114 lines (103 loc) · 3.67 KB
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
package circuit
import (
"errors"
"expvar"
"sync"
"github.com/cep21/circuit/v4/internal/evar"
)
// CommandPropertiesConstructor is a generic function that can create command properties to configure a circuit by name
// It is safe to leave not configured properties their empty value.
type CommandPropertiesConstructor func(circuitName string) Config
// Manager manages circuits with unique names
type Manager struct {
// DefaultCircuitProperties is a list of Config constructors called, in reverse order,
// to append or modify configuration for your circuit.
DefaultCircuitProperties []CommandPropertiesConstructor
circuitMap map[string]*Circuit
// mu locks circuitMap, not DefaultCircuitProperties
mu sync.RWMutex
// createMu serializes CreateCircuit (including running DefaultCircuitProperties) without holding mu, so that
// constructors may read from the Manager
createMu sync.Mutex
}
// AllCircuits returns every hystrix circuit tracked
func (h *Manager) AllCircuits() []*Circuit {
if h == nil {
return nil
}
h.mu.RLock()
defer h.mu.RUnlock()
ret := make([]*Circuit, 0, len(h.circuitMap))
for _, c := range h.circuitMap {
ret = append(ret, c)
}
return ret
}
// Var allows you to expose all your hystrix circuits on expvar
func (h *Manager) Var() expvar.Var {
return expvar.Func(func() interface{} {
ret := make(map[string]interface{})
if h == nil {
return ret
}
h.mu.RLock()
defer h.mu.RUnlock()
for k, v := range h.circuitMap {
ev := evar.ExpvarToVal(v.Var())
if ev != nil {
ret[k] = ev
}
}
return ret
})
}
// GetCircuit returns the circuit with a given name, or nil if the circuit does not exist. You should not call this
// in live code. Instead, store the circuit somewhere and use the circuit directly.
func (h *Manager) GetCircuit(name string) *Circuit {
if h == nil {
return nil
}
h.mu.RLock()
defer h.mu.RUnlock()
return h.circuitMap[name]
}
// MustCreateCircuit calls CreateCircuit, but panics if the circuit name already exists
func (h *Manager) MustCreateCircuit(name string, config ...Config) *Circuit {
c, err := h.CreateCircuit(name, config...)
if err != nil {
panic(err)
}
return c
}
var errCircuitExists = errors.New("circuit with that name already exists")
// CreateCircuit creates a new circuit, or returns an error if a circuit with that name already exists (in which case
// DefaultCircuitProperties constructors are not run). Constructors run one create at a time and may call
// GetCircuit/AllCircuits, but must not call CreateCircuit/MustCreateCircuit on the same Manager.
func (h *Manager) CreateCircuit(name string, configs ...Config) (*Circuit, error) {
// Creates are serialized by createMu (constructors are not required to be thread safe), but h.mu is *not* held
// while user constructors run so they may safely call back into the Manager (GetCircuit/AllCircuits).
h.createMu.Lock()
defer h.createMu.Unlock()
// Check for duplicates *before* running DefaultCircuitProperties: those constructors commonly have side effects
// keyed by name (e.g. rolling.StatFactory registers stats by circuit name) that a doomed duplicate create would
// otherwise clobber.
if h.GetCircuit(name) != nil {
return nil, errCircuitExists
}
finalConfig := Config{}
for _, c := range configs {
finalConfig.Merge(c)
}
// Merge in reverse order so the most recently appending constructor is more important.
for i := len(h.DefaultCircuitProperties) - 1; i >= 0; i-- {
finalConfig.Merge(h.DefaultCircuitProperties[i](name))
}
created := NewCircuitFromConfig(name, finalConfig)
h.mu.Lock()
defer h.mu.Unlock()
if h.circuitMap == nil {
h.circuitMap = make(map[string]*Circuit, 5)
}
h.circuitMap[name] = created
return created, nil
}