Skip to content

Commit b4ff634

Browse files
authored
feat(enhancement): update godoc, method signature, and cleanup unused symbols. (#936)
- add license text
1 parent c6b08cf commit b4ff634

File tree

2 files changed

+77
-54
lines changed

2 files changed

+77
-54
lines changed

circuit_breaker.go

+64-42
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// Copyright (c) 2015-present Jeevanandam M ([email protected]), All rights reserved.
2+
// resty source code and usage is governed by a MIT style
3+
// license that can be found in the LICENSE file.
4+
// SPDX-License-Identifier: MIT
5+
16
package resty
27

38
import (
@@ -7,73 +12,92 @@ import (
712
"time"
813
)
914

10-
// CircuitBreaker can be in one of three states: Closed, Open, or Half-Open.
11-
// - When the CircuitBreaker is Closed, requests are allowed to pass through.
12-
// - If a failure count threshold is reached within a specified time-frame,
13-
// the CircuitBreaker transitions to the Open state.
14-
// - When the CircuitBreaker is Open, requests are blocked.
15-
// - After a specified timeout, the CircuitBreaker transitions to the Half-Open state.
16-
// - When the CircuitBreaker is Half-Open, a single request is allowed to pass through.
17-
// - If that request fails, the CircuitBreaker returns to the Open state.
18-
// - If the number of successes reaches a specified threshold,
19-
// the CircuitBreaker transitions to the Closed state.
15+
// CircuitBreaker struct implements a state machine to monitor and manage the
16+
// states of circuit breakers. The three states are:
17+
// - Closed: requests are allowed
18+
// - Open: requests are blocked
19+
// - Half-Open: a single request is allowed to determine
20+
//
21+
// Transitions
22+
// - To Closed State: when the success count reaches the success threshold.
23+
// - To Open State: when the failure count reaches the failure threshold.
24+
// - Half-Open Check: when the specified timeout reaches, a single request is allowed
25+
// to determine the transition state; if failed, it goes back to the open state.
2026
type CircuitBreaker struct {
21-
policies []CircuitBreakerPolicy
22-
timeout time.Duration
23-
failThreshold, successThreshold uint32
24-
25-
state atomic.Value // circuitBreakerState
26-
failCount, successCount atomic.Uint32
27-
lastFail time.Time
27+
policies []CircuitBreakerPolicy
28+
timeout time.Duration
29+
failureThreshold uint32
30+
successThreshold uint32
31+
state atomic.Value // circuitBreakerState
32+
failureCount atomic.Uint32
33+
successCount atomic.Uint32
34+
lastFailureAt time.Time
2835
}
2936

30-
// NewCircuitBreaker creates a new [CircuitBreaker] with default settings.
37+
// NewCircuitBreaker method creates a new [CircuitBreaker] with default settings.
38+
//
3139
// The default settings are:
32-
// - Timeout: 10 seconds
33-
// - FailThreshold: 3
34-
// - SuccessThreshold: 1
35-
// - Policies: CircuitBreaker5xxPolicy
40+
// - Timeout: 10 seconds
41+
// - FailThreshold: 3
42+
// - SuccessThreshold: 1
43+
// - Policies: CircuitBreaker5xxPolicy
3644
func NewCircuitBreaker() *CircuitBreaker {
3745
cb := &CircuitBreaker{
3846
policies: []CircuitBreakerPolicy{CircuitBreaker5xxPolicy},
3947
timeout: 10 * time.Second,
40-
failThreshold: 3,
48+
failureThreshold: 3,
4149
successThreshold: 1,
4250
}
4351
cb.state.Store(circuitBreakerStateClosed)
4452
return cb
4553
}
4654

47-
// SetPolicies sets the CircuitBreakerPolicy's that the [CircuitBreaker] will use to determine whether a response is a failure.
48-
func (cb *CircuitBreaker) SetPolicies(policies []CircuitBreakerPolicy) *CircuitBreaker {
55+
// SetPolicies method sets the one or more given CircuitBreakerPolicy(s) into
56+
// [CircuitBreaker], which will be used to determine whether a request is failed
57+
// or successful by evaluating the response instance.
58+
//
59+
// // set one policy
60+
// cb.SetPolicies(CircuitBreaker5xxPolicy)
61+
//
62+
// // set multiple polices
63+
// cb.SetPolicies(policy1, policy2, policy3)
64+
//
65+
// // if you have slice, do
66+
// cb.SetPolicies(policies...)
67+
//
68+
// NOTE: This method overwrites the policies with the given new ones. See [CircuitBreaker.AddPolicies]
69+
func (cb *CircuitBreaker) SetPolicies(policies ...CircuitBreakerPolicy) *CircuitBreaker {
4970
cb.policies = policies
5071
return cb
5172
}
5273

53-
// SetTimeout sets the timeout duration for the [CircuitBreaker].
74+
// SetTimeout method sets the timeout duration for the [CircuitBreaker]. When the
75+
// timeout reaches, a single request is allowed to determine the state.
5476
func (cb *CircuitBreaker) SetTimeout(timeout time.Duration) *CircuitBreaker {
5577
cb.timeout = timeout
5678
return cb
5779
}
5880

59-
// SetFailThreshold sets the number of failures that must occur within the timeout duration for the [CircuitBreaker] to
60-
// transition to the Open state.
61-
func (cb *CircuitBreaker) SetFailThreshold(threshold uint32) *CircuitBreaker {
62-
cb.failThreshold = threshold
81+
// SetFailureThreshold method sets the number of failures that must occur within the
82+
// timeout duration for the [CircuitBreaker] to transition to the Open state.
83+
func (cb *CircuitBreaker) SetFailureThreshold(threshold uint32) *CircuitBreaker {
84+
cb.failureThreshold = threshold
6385
return cb
6486
}
6587

66-
// SetSuccessThreshold sets the number of successes that must occur to transition the [CircuitBreaker] from the Half-Open state
67-
// to the Closed state.
88+
// SetSuccessThreshold method sets the number of successes that must occur to transition
89+
// the [CircuitBreaker] from the Half-Open state to the Closed state.
6890
func (cb *CircuitBreaker) SetSuccessThreshold(threshold uint32) *CircuitBreaker {
6991
cb.successThreshold = threshold
7092
return cb
7193
}
7294

73-
// CircuitBreakerPolicy is a function that determines whether a response should trip the [CircuitBreaker].
95+
// CircuitBreakerPolicy is a function type that determines whether a response should
96+
// trip the [CircuitBreaker].
7497
type CircuitBreakerPolicy func(resp *http.Response) bool
7598

76-
// CircuitBreaker5xxPolicy is a [CircuitBreakerPolicy] that trips the [CircuitBreaker] if the response status code is 500 or greater.
99+
// CircuitBreaker5xxPolicy is a [CircuitBreakerPolicy] that trips the [CircuitBreaker] if
100+
// the response status code is 500 or greater.
77101
func CircuitBreaker5xxPolicy(resp *http.Response) bool {
78102
return resp.StatusCode > 499
79103
}
@@ -118,17 +142,17 @@ func (cb *CircuitBreaker) applyPolicies(resp *http.Response) {
118142
}
119143

120144
if failed {
121-
if cb.failCount.Load() > 0 && time.Since(cb.lastFail) > cb.timeout {
122-
cb.failCount.Store(0)
145+
if cb.failureCount.Load() > 0 && time.Since(cb.lastFailureAt) > cb.timeout {
146+
cb.failureCount.Store(0)
123147
}
124148

125149
switch cb.getState() {
126150
case circuitBreakerStateClosed:
127-
failCount := cb.failCount.Add(1)
128-
if failCount >= cb.failThreshold {
151+
failCount := cb.failureCount.Add(1)
152+
if failCount >= cb.failureThreshold {
129153
cb.open()
130154
} else {
131-
cb.lastFail = time.Now()
155+
cb.lastFailureAt = time.Now()
132156
}
133157
case circuitBreakerStateHalfOpen:
134158
cb.open()
@@ -144,8 +168,6 @@ func (cb *CircuitBreaker) applyPolicies(resp *http.Response) {
144168
}
145169
}
146170
}
147-
148-
return
149171
}
150172

151173
func (cb *CircuitBreaker) open() {
@@ -157,7 +179,7 @@ func (cb *CircuitBreaker) open() {
157179
}
158180

159181
func (cb *CircuitBreaker) changeState(state circuitBreakerState) {
160-
cb.failCount.Store(0)
182+
cb.failureCount.Store(0)
161183
cb.successCount.Store(0)
162184
cb.state.Store(state)
163185
}

client_test.go

+13-12
Original file line numberDiff line numberDiff line change
@@ -1442,14 +1442,15 @@ func TestClientCircuitBreaker(t *testing.T) {
14421442

14431443
failThreshold := uint32(2)
14441444
successThreshold := uint32(1)
1445-
timeout := 1 * time.Second
1445+
timeout := 500 * time.Millisecond
14461446

1447-
c := dcnl().SetCircuitBreaker(
1448-
NewCircuitBreaker().
1449-
SetTimeout(timeout).
1450-
SetFailThreshold(failThreshold).
1451-
SetSuccessThreshold(successThreshold).
1452-
SetPolicies([]CircuitBreakerPolicy{CircuitBreaker5xxPolicy}))
1447+
cb := NewCircuitBreaker().
1448+
SetTimeout(timeout).
1449+
SetFailureThreshold(failThreshold).
1450+
SetSuccessThreshold(successThreshold).
1451+
SetPolicies(CircuitBreaker5xxPolicy)
1452+
1453+
c := dcnl().SetCircuitBreaker(cb)
14531454

14541455
for i := uint32(0); i < failThreshold; i++ {
14551456
_, err := c.R().Get(ts.URL + "/500")
@@ -1463,7 +1464,7 @@ func TestClientCircuitBreaker(t *testing.T) {
14631464
time.Sleep(timeout + 1*time.Millisecond)
14641465
assertEqual(t, circuitBreakerStateHalfOpen, c.circuitBreaker.getState())
14651466

1466-
resp, err = c.R().Get(ts.URL + "/500")
1467+
_, err = c.R().Get(ts.URL + "/500")
14671468
assertError(t, err)
14681469
assertEqual(t, circuitBreakerStateOpen, c.circuitBreaker.getState())
14691470

@@ -1480,13 +1481,13 @@ func TestClientCircuitBreaker(t *testing.T) {
14801481
assertNil(t, err)
14811482
assertEqual(t, http.StatusOK, resp.StatusCode())
14821483

1483-
resp, err = c.R().Get(ts.URL + "/500")
1484+
_, err = c.R().Get(ts.URL + "/500")
14841485
assertError(t, err)
1485-
assertEqual(t, uint32(1), c.circuitBreaker.failCount.Load())
1486+
assertEqual(t, uint32(1), c.circuitBreaker.failureCount.Load())
14861487

14871488
time.Sleep(timeout)
14881489

1489-
resp, err = c.R().Get(ts.URL + "/500")
1490+
_, err = c.R().Get(ts.URL + "/500")
14901491
assertError(t, err)
1491-
assertEqual(t, uint32(1), c.circuitBreaker.failCount.Load())
1492+
assertEqual(t, uint32(1), c.circuitBreaker.failureCount.Load())
14921493
}

0 commit comments

Comments
 (0)