Skip to content

Commit 5895317

Browse files
committed
stability/circuit-breaker: revamp the old example
1 parent f7e3262 commit 5895317

File tree

5 files changed

+104
-293
lines changed

5 files changed

+104
-293
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ A curated collection of idiomatic design & application patterns for Go language.
8888
| Pattern | Description | Status |
8989
|:-------:|:----------- |:------:|
9090
| [Bulkheads](/stability/bulkhead.md) | Enforces a principle of failure containment (i.e. prevents cascading failures) ||
91-
| [Circuit-Breaker](/stability/circuit_breaker.md) | Stops the flow of the requests when requests are likely to fail ||
91+
| [Circuit-Breaker](/stability/circuit-breaker.md) | Stops the flow of the requests when requests are likely to fail ||
9292
| [Deadline](/stability/deadline.md) | Allows clients to stop waiting for a response once the probability of response becomes low (e.g. after waiting 10 seconds for a page refresh) ||
9393
| [Fail-Fast](/stability/fail_fast.md) | Checks the availability of required resources at the start of a request and fails if the requirements are not satisfied ||
9494
| [Handshaking](/stability/handshaking.md) | Asks a component if it can take any more load, if it can't the request is declined ||

SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
* [Push & Pull](/messaging/push_pull.md)
5252
* [Stability Patterns](/README.md#stability-patterns)
5353
* [Bulkheads](/stability/bulkhead.md)
54-
* [Circuit-Breaker](/stability/circuit_breaker.md)
54+
* [Circuit-Breaker](/stability/circuit-breaker.md)
5555
* [Deadline](/stability/deadline.md)
5656
* [Fail-Fast](/stability/fail_fast.md)
5757
* [Handshaking](/stability/handshaking.md)

stability/circuit-breaker.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Circuit Breaker Pattern
2+
3+
Similar to electrical fuses that prevent fires when a circuit that is connected
4+
to the electrical grid starts drawing a high amount of power which causes the
5+
wires to heat up and combust, the circuit breaker design pattern is a fail-first
6+
mechanism that shuts down the circuit, request/response relationship or a
7+
service in the case of software development, to prevent bigger failures.
8+
9+
**Note:** The words "circuit" and "service" are used synonymously throught this
10+
document.
11+
12+
## Implementation
13+
14+
Below is the implementation of a very simple circuit breaker to illustrate the purpose
15+
of the circuit breaker design pattern.
16+
17+
### Operation Counter
18+
19+
`circuit.Counter` is a simple counter that records success and failure states of
20+
a circuit along with a timestamp and calculates the consecutive number of
21+
failures.
22+
23+
```go
24+
package circuit
25+
26+
import (
27+
"time"
28+
)
29+
30+
type State int
31+
32+
const (
33+
UnknownState State = iota
34+
FailureState
35+
SuccessState
36+
)
37+
38+
type Counter interface {
39+
Count(State)
40+
ConsecutiveFailures() uint32
41+
LastActivity() time.Time
42+
Reset()
43+
}
44+
```
45+
46+
### Circuit Breaker
47+
48+
Circuit is wrapped using the `circuit.Breaker` closure that keeps an internal operation counter.
49+
It returns a fast error if the circuit has failed consecutively more than the specified threshold.
50+
After a while it retries the request and records it.
51+
52+
**Note:** Context type is used here to carry deadlines, cancelation signals, and
53+
other request-scoped values across API boundaries and between processes.
54+
55+
```go
56+
package circuit
57+
58+
import (
59+
"context"
60+
"time"
61+
)
62+
63+
type Circuit func(context.Context) error
64+
65+
func Breaker(c Circuit, failureThreshold uint32) Circuit {
66+
cnt := NewCounter()
67+
68+
return func(ctx context) error {
69+
if cnt.ConsecutiveFailures() >= failureThreshold {
70+
canRetry := func(cnt Counter) {
71+
backoffLevel := Cnt.ConsecutiveFailures() - failureThreshold
72+
73+
// Calculates when should the circuit breaker resume propagating requests
74+
// to the service
75+
shouldRetryAt := cnt.LastActivity().Add(time.Seconds * 2 << backoffLevel)
76+
77+
return time.Now().After(shouldRetryAt)
78+
}
79+
80+
if !canRetry(cnt) {
81+
// Fails fast instead of propagating requests to the circuit since
82+
// not enough time has passed since the last failure to retry
83+
return ErrServiceUnavailable
84+
}
85+
}
86+
87+
// Unless the failure threshold is exceeded the wrapped service mimics the
88+
// old behavior and the difference in behavior is seen after consecutive failures
89+
if err := c(ctx); err != nil {
90+
cnt.Count(FailureState)
91+
return err
92+
}
93+
94+
cnt.Count(SuccessState)
95+
return nil
96+
}
97+
}
98+
```
99+
100+
## Related Works
101+
102+
- [sony/gobreaker](https://github.com/sony/go-breaker) is a well-tested and intuitive circuit breaker implementation for real-world use cases.

stability/circuit_breaker.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)