-
Notifications
You must be signed in to change notification settings - Fork 18
/
circuitbreaker.go
168 lines (147 loc) · 4.33 KB
/
circuitbreaker.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package main
import (
"errors"
"fmt"
"github.com/peterbourgon/g2s"
cb "github.com/rubyist/circuitbreaker"
"io/ioutil"
"log"
"time"
)
func ExampleErrorThresholdBreaker() {
// This example sets up a ThresholdBreaker that will trip if remoteCall returns
// an error 10 times in a row. The error returned by Call() will be the error
// returned by remoteCall, unless the breaker has been tripped, in which case
// it will return ErrBreakerOpen.
breaker := cb.NewThresholdBreaker(10)
err := breaker.Call(errorCall, 0)
if err != nil {
log.Fatal(err)
}
}
func ExampleThresholdBreaker() {
// This example sets up a ThresholdBreaker that will trip if remoteCall returns
// an error 10 times in a row. The error returned by Call() will be the error
// returned by remoteCall, unless the breaker has been tripped, in which case
// it will return ErrBreakerOpen.
breaker := cb.NewThresholdBreaker(10)
err := breaker.Call(remoteCall, 0)
if err != nil {
log.Fatal(err)
}
}
func ExampleTimeoutBreaker() {
// This example sets up a TimeoutBreaker that will trip if remoteCall returns
// an error OR takes longer than one second 10 times in a row. The error returned
// by Call() will be the error returned by remoteCall with two exceptions: if
// remoteCall takes longer than one second the return value will be ErrBreakerTimeout,
// if the breaker has been tripped the return value will be ErrBreakerOpen.
breaker := cb.NewThresholdBreaker(10)
err := breaker.Call(remoteCall, time.Second)
if err != nil {
log.Fatal(err)
}
}
func ExampleConsecutiveBreaker() {
// This example sets up a FrequencyBreaker that will trip if remoteCall returns
// an error 10 times in a row within a period of 2 minutes.
breaker := cb.NewConsecutiveBreaker(10)
err := breaker.Call(remoteCall, 0)
if err != nil {
log.Fatal(err)
}
}
func ExampleHTTPClient() {
// This example sets up an HTTP client wrapped in a TimeoutBreaker. The breaker
// will trip with the same behavior as TimeoutBreaker.
client := cb.NewHTTPClient(time.Second*5, 10, nil)
resp, err := client.Get("http://example.com/resource.json")
if err != nil {
log.Fatal(err)
}
resource, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", resource)
}
func ExampleBreaker_events() {
// This example demonstrates the BreakerTripped and BreakerReset callbacks. These are
// available on all breaker types.
breaker := cb.NewThresholdBreaker(10)
events := breaker.Subscribe()
go func() {
for {
e := <-events
switch e {
case cb.BreakerTripped:
log.Println("breaker tripped")
case cb.BreakerReset:
log.Println("breaker reset")
case cb.BreakerFail:
log.Println("breaker fail")
case cb.BreakerReady:
log.Println("breaker ready")
}
}
}()
breaker.Fail()
//breaker.Reset()
}
func ExamplePanel() {
// This example demonstrates using a Panel to aggregate and manage circuit breakers.
breaker1 := cb.NewThresholdBreaker(10)
breaker2 := cb.NewRateBreaker(0.95, 100)
panel := cb.NewPanel()
panel.Add("breaker1", breaker1)
panel.Add("breaker2", breaker2)
// Elsewhere in the code ...
b1, _ := panel.Get("breaker1")
b1.Call(func() error {
// Do some work
return nil
}, 0)
b2, _ := panel.Get("breaker2")
b2.Call(func() error {
// Do some work
return nil
}, 0)
}
func ExamplePanel_stats() {
// This example demonstrates how to push circuit breaker stats to statsd via a Panel.
// This example uses g2s. Anything conforming to the Statter interface can be used.
s, err := g2s.Dial("udp", "statsd-server:8125")
if err != nil {
log.Fatal(err)
}
breaker := cb.NewThresholdBreaker(10)
panel := cb.NewPanel()
panel.Statter = s
panel.StatsPrefixf = "sys.production.%s"
panel.Add("x", breaker)
breaker.Trip() // sys.production.circuit.x.tripped
breaker.Reset() // sys.production.circuit.x.reset, sys.production.circuit.x.trip-time
breaker.Fail() // sys.production.circuit.x.fail
breaker.Ready() // sys.production.circuit.x.ready (if it's tripped and ready to retry)
}
func remoteCall() error {
// Expensive remote call
return nil
}
func errorCall() error {
// Expensive remote call
return errors.New("error")
}
func main() {
breaker := cb.NewThresholdBreaker(10)
i := 1
for i <= 12 {
if breaker.Ready() {
log.Println(breaker.Call(errorCall, 0))
} else {
log.Println("circuit breaker is open")
}
i++
}
}