@@ -28,47 +28,57 @@ import (
28
28
"github.com/alibaba/sentinel-golang/core/circuitbreaker"
29
29
)
30
30
31
- var callCounts = make (map [string ]int )
32
- var recoverCount int
33
- var mu sync.Mutex
31
+ type dummyCall struct {
32
+ callCounts map [string ]int
33
+ recoverCount int
34
+ mtx sync.Mutex
35
+ }
36
+
37
+ func newDummyCall () * dummyCall {
38
+ return & dummyCall {
39
+ callCounts : make (map [string ]int ),
40
+ }
41
+ }
34
42
35
- func registerAddress (address string , n int ) {
36
- mu .Lock ()
37
- defer mu .Unlock ()
38
- callCounts [address ] = n
43
+ func ( d * dummyCall ) registerAddress (address string , n int ) {
44
+ d . mtx .Lock ()
45
+ defer d . mtx .Unlock ()
46
+ d . callCounts [address ] = n
39
47
}
40
48
41
- // dummyCall checks whether the node address has returned to normal.
49
+ // dummyCall's Check checks whether the node address has returned to normal.
42
50
// It returns to normal when the value recorded in callCounts decreases to 0.
43
- func dummyCall (address string ) bool {
44
- mu .Lock ()
45
- defer mu .Unlock ()
46
- if _ , ok := callCounts [address ]; ok {
47
- callCounts [address ]--
51
+ func ( d * dummyCall ) Check (address string ) bool {
52
+ d . mtx .Lock ()
53
+ defer d . mtx .Unlock ()
54
+ if _ , ok := d . callCounts [address ]; ok {
55
+ d . callCounts [address ]--
48
56
time .Sleep (100 * time .Millisecond ) // simulate network latency
49
- if callCounts [address ] == 0 {
57
+ if d . callCounts [address ] == 0 {
50
58
fmt .Printf ("%s successfully reconnected\n " , address )
51
- recoverCount ++
59
+ d . recoverCount ++
52
60
return true
53
61
}
54
62
return false
55
63
}
64
+ fmt .Println (d .callCounts )
56
65
panic ("Attempting to call an unregistered node address." )
66
+ return false
57
67
}
58
68
59
- func getRecoverCount () int {
60
- mu .Lock ()
61
- defer mu .Unlock ()
62
- return recoverCount
69
+ func ( d * dummyCall ) getRecoverCount () int {
70
+ d . mtx .Lock ()
71
+ defer d . mtx .Unlock ()
72
+ return d . recoverCount
63
73
}
64
74
65
- func addOutlierRuleForRetryer (resource string , n , internal uint32 ) {
75
+ func addOutlierRuleForRetryer (resource string , n , internal uint32 , f RecoveryCheckFunc ) {
66
76
updateMux .Lock ()
67
77
defer updateMux .Unlock ()
68
78
outlierRules [resource ] = & Rule {
69
79
MaxRecoveryAttempts : n ,
70
80
RecoveryIntervalMs : internal ,
71
- RecoveryCheckFunc : dummyCall ,
81
+ RecoveryCheckFunc : f ,
72
82
}
73
83
}
74
84
@@ -124,14 +134,15 @@ func setNodeBreaker(resource string, node string, breaker *MockCircuitBreaker) {
124
134
// Construct two dummy node addresses: the first one recovers after the third check,
125
135
// and the second one recovers after math.MaxInt32 checks. Observe the changes in the
126
136
// circuit breaker and callCounts status for the first node before and after recovery.
127
- func TestRetryer (t * testing.T ) {
128
- resource := "testResource "
137
+ func testRetryer (t * testing.T ) {
138
+ resource := "testResource0 "
129
139
nodes := []string {"node0" , "node1" }
130
140
var internal , n uint32 = 1000 , 3
131
- registerAddress (nodes [0 ], int (n ))
132
- registerAddress (nodes [1 ], math .MaxInt32 )
141
+ d := newDummyCall ()
142
+ d .registerAddress (nodes [0 ], int (n ))
143
+ d .registerAddress (nodes [1 ], math .MaxInt32 )
133
144
134
- addOutlierRuleForRetryer (resource , n , internal )
145
+ addOutlierRuleForRetryer (resource , n , internal , d . Check )
135
146
retryer := getRetryerOfResource (resource )
136
147
retryer .scheduleNodes (nodes )
137
148
@@ -140,31 +151,32 @@ func TestRetryer(t *testing.T) {
140
151
setNodeBreaker (resource , nodes [0 ], mockCB )
141
152
142
153
minDuration := time .Duration (n * (n + 1 ) / 2 * internal * 1e6 )
143
- for getRecoverCount () < 1 {
154
+ for d . getRecoverCount () < 1 {
144
155
time .Sleep (minDuration )
145
156
}
146
157
assert .Equal (t , len (nodes )- 1 , len (retryer .counts ))
147
158
mockCB .AssertExpectations (t )
148
159
}
149
160
150
- func TestRetryerConcurrent (t * testing.T ) {
151
- resource := "testResource "
161
+ func testRetryerConcurrent (t * testing.T ) {
162
+ resource := "testResource1 "
152
163
nodes := generateNodes (100 ) // Generate 100 nodes
153
164
var internal , n uint32 = 1000 , 3
165
+ d := newDummyCall ()
154
166
mockCBs := make ([]* MockCircuitBreaker , 0 , len (nodes )/ 2 )
155
167
for i , node := range nodes {
156
168
if i % 2 == 0 {
157
169
mockCB := new (MockCircuitBreaker )
158
170
mockCB .On ("OnRequestComplete" , mock .AnythingOfType ("uint64" ), nil ).Return ()
159
171
setNodeBreaker (resource , node , mockCB )
160
172
mockCBs = append (mockCBs , mockCB )
161
- registerAddress (node , int (n ))
173
+ d . registerAddress (node , int (n ))
162
174
} else {
163
- registerAddress (node , math .MaxInt32 )
175
+ d . registerAddress (node , math .MaxInt32 )
164
176
}
165
177
}
166
-
167
- addOutlierRuleForRetryer (resource , n , internal )
178
+ fmt . Println ( d . callCounts )
179
+ addOutlierRuleForRetryer (resource , n , internal , d . Check )
168
180
retryer := getRetryerOfResource (resource )
169
181
numGoroutines := 10
170
182
var wg sync.WaitGroup
@@ -187,7 +199,7 @@ func TestRetryerConcurrent(t *testing.T) {
187
199
assert .Equal (t , len (nodes ), len (retryer .counts ))
188
200
189
201
minDuration := time .Duration (n * (n + 1 ) / 2 * internal * 1e6 )
190
- for getRecoverCount () < len (nodes )/ 2 {
202
+ for d . getRecoverCount () < len (nodes )/ 2 {
191
203
time .Sleep (minDuration )
192
204
}
193
205
assert .Equal (t , len (nodes )/ 2 , len (retryer .counts ))
@@ -196,14 +208,15 @@ func TestRetryerConcurrent(t *testing.T) {
196
208
}
197
209
}
198
210
199
- func TestRetryerCh (t * testing.T ) {
211
+ func testRetryerCh (t * testing.T ) {
200
212
nodes := []string {"node0" , "node1" }
201
- resource := "testResource "
213
+ resource := "testResource2 "
202
214
var internal , n uint32 = 1000 , 3
203
- registerAddress (nodes [0 ], int (n ))
204
- registerAddress (nodes [1 ], math .MaxInt32 )
215
+ d := newDummyCall ()
216
+ d .registerAddress (nodes [0 ], int (n ))
217
+ d .registerAddress (nodes [1 ], math .MaxInt32 )
205
218
206
- addOutlierRuleForRetryer (resource , n , internal )
219
+ addOutlierRuleForRetryer (resource , n , internal , d . Check )
207
220
retryer := getRetryerOfResource (resource )
208
221
209
222
mockCB := new (MockCircuitBreaker )
@@ -213,9 +226,15 @@ func TestRetryerCh(t *testing.T) {
213
226
retryerCh <- task {nodes , resource }
214
227
215
228
minDuration := time .Duration (n * (n + 1 ) / 2 * internal * 1e6 )
216
- for getRecoverCount () < 1 {
229
+ for d . getRecoverCount () < 1 {
217
230
time .Sleep (minDuration )
218
231
}
219
232
assert .Equal (t , len (nodes )- 1 , len (retryer .counts ))
220
233
mockCB .AssertExpectations (t )
221
234
}
235
+
236
+ func TestRetryerAll (t * testing.T ) {
237
+ t .Run ("TestRetryer" , testRetryer )
238
+ t .Run ("TestRetryerConcurrent" , testRetryerConcurrent )
239
+ t .Run ("TestRetryerCh" , testRetryerCh )
240
+ }
0 commit comments