-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose CircuitBreaker current condition (or state) to the metrics recorder interface and Prometheus. #25
base: master
Are you sure you want to change the base?
Expose CircuitBreaker current condition (or state) to the metrics recorder interface and Prometheus. #25
Changes from all commits
b5e2dd3
4d29958
fcfae81
57a6f52
8978c16
db7bf6a
2bf49fb
c89af62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,14 +10,30 @@ import ( | |
"github.com/slok/goresilience/metrics" | ||
) | ||
|
||
type state string | ||
type state uint | ||
|
||
const ( | ||
stateOpen state = "open" | ||
stateHalfOpen state = "halfopen" | ||
stateClosed state = "closed" | ||
stateNew state = iota | ||
stateOpen | ||
stateHalfOpen | ||
stateClosed | ||
) | ||
|
||
var stateStrings = []string { | ||
"new", | ||
"open", | ||
"halfopen", | ||
"closed", | ||
} | ||
|
||
func (st state) label () string { | ||
return stateStrings[st] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 things:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll have to read up on the Stringer interface but it feels a more natural fit. Will consider both when refactoring. |
||
} | ||
|
||
func (st state) condition () int { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that we could remove the integer usage for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, will refactor accordingly. (Am I right in that you're happy with the use of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
return int(st) | ||
} | ||
|
||
// Config is the configuration of the circuit breaker. | ||
type Config struct { | ||
// ErrorPercentThresholdToOpen is the error percent based on total execution requests | ||
|
@@ -124,7 +140,7 @@ func NewMiddleware(cfg Config) goresilience.Middleware { | |
|
||
return func(next goresilience.Runner) goresilience.Runner { | ||
return &circuitbreaker{ | ||
state: stateClosed, | ||
state: stateNew, | ||
recorder: newBucketWindow(cfg.MetricsSlidingWindowBucketQuantity, cfg.MetricsBucketDuration), | ||
stateStarted: time.Now(), | ||
cfg: cfg, | ||
|
@@ -157,6 +173,9 @@ func (c *circuitbreaker) Run(ctx context.Context, f goresilience.Func) error { | |
func (c *circuitbreaker) preDecideState(metricsRec metrics.Recorder) { | ||
state := c.getState() | ||
switch state { | ||
case stateNew: | ||
// Close the breaker as this is the first time through and generate a statistic. | ||
c.moveState(stateClosed, metricsRec) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As stated before, the initial state of a circuit breaker is closed, so the above change of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, although it's coupled to my comment above. |
||
case stateOpen: | ||
// Check if the circuit has been the required time in closed. If yes then | ||
// we move to half open state. | ||
|
@@ -223,7 +242,8 @@ func (c *circuitbreaker) moveState(state state, metricsRec metrics.Recorder) { | |
|
||
// Only change if the state changed. | ||
if c.state != state { | ||
metricsRec.IncCircuitbreakerState(string(state)) | ||
metricsRec.IncCircuitbreakerState(state.label()) | ||
metricsRec.SetCircuitbreakerCurrentState(state.condition()) | ||
|
||
c.state = state | ||
c.stateStarted = time.Now() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New state is the same as a closed state because a new circuitbreaker starts in a closed state. Do you have a use case where you need to know the difference between new and closed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My choice to implement
stateNew
and the transition tostateClosed
on first traversal provided a mechanism to ensure that the state of the breaker was recorded on first use.Otherwise, I found that there are no state metrics recorded until the first state change occurs.
I might take a few moments to review how I'm using the circuitbreaker instance by my application.