@@ -20,18 +20,17 @@ import (
20
20
type waitAlgo struct {
21
21
mutex * sync.Mutex // required for *rand.Rand usage
22
22
random * rand.Rand
23
+ base time.Duration // base wait time
24
+ cap time.Duration // maximum wait time
23
25
}
24
26
25
27
var random * rand.Rand
26
28
var defaultWaitAlgo * waitAlgo
27
29
28
- var endpointsEligibleForRetry = []string {
30
+ var authEndpoints = []string {
29
31
loginRequestPath ,
30
32
tokenRequestPath ,
31
33
authenticatorRequestPath ,
32
- queryRequestPath ,
33
- abortRequestPath ,
34
- sessionRequestPath ,
35
34
}
36
35
37
36
var clientErrorsStatusCodesEligibleForRetry = []int {
@@ -43,7 +42,7 @@ var clientErrorsStatusCodesEligibleForRetry = []int{
43
42
44
43
func init () {
45
44
random = rand .New (rand .NewSource (time .Now ().UnixNano ()))
46
- defaultWaitAlgo = & waitAlgo {mutex : & sync.Mutex {}, random : random }
45
+ defaultWaitAlgo = & waitAlgo {mutex : & sync.Mutex {}, random : random , base : 5 * time . Second , cap : 160 * time . Second }
47
46
}
48
47
49
48
const (
@@ -205,12 +204,30 @@ func isQueryRequest(url *url.URL) bool {
205
204
}
206
205
207
206
// jitter backoff in seconds
208
- func (w * waitAlgo ) calculateWaitBeforeRetry (attempt int , currWaitTime float64 ) float64 {
207
+ func (w * waitAlgo ) calculateWaitBeforeRetryForAuthRequest (attempt int , currWaitTimeDuration time. Duration ) time. Duration {
209
208
w .mutex .Lock ()
210
209
defer w .mutex .Unlock ()
211
- jitterAmount := w .getJitter (currWaitTime )
212
- jitteredSleepTime := chooseRandomFromRange (currWaitTime + jitterAmount , math .Pow (2 , float64 (attempt ))+ jitterAmount )
213
- return jitteredSleepTime
210
+ currWaitTimeInSeconds := currWaitTimeDuration .Seconds ()
211
+ jitterAmount := w .getJitter (currWaitTimeInSeconds )
212
+ jitteredSleepTime := chooseRandomFromRange (currWaitTimeInSeconds + jitterAmount , math .Pow (2 , float64 (attempt ))+ jitterAmount )
213
+ return time .Duration (jitteredSleepTime * float64 (time .Second ))
214
+ }
215
+
216
+ func (w * waitAlgo ) calculateWaitBeforeRetry (attempt int , sleep time.Duration ) time.Duration {
217
+ w .mutex .Lock ()
218
+ defer w .mutex .Unlock ()
219
+ t := 3 * sleep - w .base
220
+ switch {
221
+ case t > 0 :
222
+ return durationMin (w .cap , randSecondDuration (t )+ w .base )
223
+ case t < 0 :
224
+ return durationMin (w .cap , randSecondDuration (- t )+ 3 * sleep )
225
+ }
226
+ return w .base
227
+ }
228
+
229
+ func randSecondDuration (n time.Duration ) time.Duration {
230
+ return time .Duration (random .Int63n (int64 (n / time .Second ))) * time .Second
214
231
}
215
232
216
233
func (w * waitAlgo ) getJitter (currWaitTime float64 ) float64 {
@@ -284,7 +301,7 @@ func (r *retryHTTP) execute() (res *http.Response, err error) {
284
301
totalTimeout := r .timeout
285
302
logger .WithContext (r .ctx ).Infof ("retryHTTP.totalTimeout: %v" , totalTimeout )
286
303
retryCounter := 0
287
- sleepTime := 1.0 // seconds
304
+ sleepTime := time . Duration ( time . Second )
288
305
clientStartTime := strconv .FormatInt (r .currentTimeProvider .currentTime (), 10 )
289
306
290
307
var requestGUIDReplacer requestGUIDReplacer
@@ -324,12 +341,16 @@ func (r *retryHTTP) execute() (res *http.Response, err error) {
324
341
}
325
342
// uses exponential jitter backoff
326
343
retryCounter ++
327
- sleepTime = defaultWaitAlgo .calculateWaitBeforeRetry (retryCounter , sleepTime )
344
+ if isLoginRequest (req ) {
345
+ sleepTime = defaultWaitAlgo .calculateWaitBeforeRetryForAuthRequest (retryCounter , sleepTime )
346
+ } else {
347
+ sleepTime = defaultWaitAlgo .calculateWaitBeforeRetry (retryCounter , sleepTime )
348
+ }
328
349
329
350
if totalTimeout > 0 {
330
351
logger .WithContext (r .ctx ).Infof ("to timeout: %v" , totalTimeout )
331
352
// if any timeout is set
332
- totalTimeout -= time . Duration ( sleepTime * float64 ( time . Second ))
353
+ totalTimeout -= sleepTime
333
354
if totalTimeout <= 0 || retryCounter > r .maxRetryCount {
334
355
if err != nil {
335
356
return nil , err
@@ -360,7 +381,7 @@ func (r *retryHTTP) execute() (res *http.Response, err error) {
360
381
logger .WithContext (r .ctx ).Infof ("sleeping %v. to timeout: %v. retrying" , sleepTime , totalTimeout )
361
382
logger .WithContext (r .ctx ).Infof ("retry count: %v, retry reason: %v" , retryCounter , retryReason )
362
383
363
- await := time .NewTimer (time . Duration ( sleepTime * float64 ( time . Second )) )
384
+ await := time .NewTimer (sleepTime )
364
385
select {
365
386
case <- await .C :
366
387
// retry the request
@@ -378,10 +399,13 @@ func isRetryableError(req *http.Request, res *http.Response, err error) (bool, e
378
399
if res == nil || req == nil {
379
400
return false , err
380
401
}
381
- isRetryableURL := contains (endpointsEligibleForRetry , req .URL .Path )
382
- return isRetryableURL && isRetryableStatus (res .StatusCode ), err
402
+ return isRetryableStatus (res .StatusCode ), err
383
403
}
384
404
385
405
func isRetryableStatus (statusCode int ) bool {
386
406
return (statusCode >= 500 && statusCode < 600 ) || contains (clientErrorsStatusCodesEligibleForRetry , statusCode )
387
407
}
408
+
409
+ func isLoginRequest (req * http.Request ) bool {
410
+ return contains (authEndpoints , req .URL .Path )
411
+ }
0 commit comments