-
Notifications
You must be signed in to change notification settings - Fork 0
/
retry_strategy.go
80 lines (70 loc) · 2.63 KB
/
retry_strategy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package httpify
import (
"math"
"math/rand"
"net/http"
"time"
)
// RetryStrategy defines how long to wait between retries.
type RetryStrategy func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration
// DefaultRetryStrategy implements exponential retryStrategy based on attempt count, bounded by min and max durations.
func DefaultRetryStrategy() RetryStrategy {
return func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
sleep := time.Duration(math.Pow(2, float64(attemptNum)) * float64(min))
if sleep > max {
return max
}
return sleep
}
}
// jitterRetryStrategy returns a Randomized duration within the range of min to max.
func jitterRetryStrategy(min, max time.Duration, attemptNum int, randSource *rand.Rand) time.Duration {
randomized := randSource.Float64() * float64(max-min)
jitterDuration := time.Duration(int64(randomized) + int64(min))
return jitterDuration * time.Duration(attemptNum+1)
}
// LinearRandomizedRetryStrategy adds random randomized to linear retryStrategy.
func LinearRandomizedRetryStrategy() RetryStrategy {
randSource := newRandSource()
return func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
if max <= min {
return min * time.Duration(attemptNum+1)
}
// Calculate Randomized retryStrategy
RandomizedDuration := jitterRetryStrategy(min, max, attemptNum, randSource)
// Ensure the Randomized retryStrategy does not exceed the max duration
if RandomizedDuration > max {
return max
}
return RandomizedDuration
}
}
// RandomizedFullRetryStrategy implements capped exponential retryStrategy with full randomized.
func RandomizedFullRetryStrategy() RetryStrategy {
randSource := newRandSource()
return func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
duration := attemptNum * 1000000000 << 1
randomized := randSource.Intn(duration-attemptNum) + int(min)
if randomized > int(max) {
return max
}
return time.Duration(randomized)
}
}
// ExponentialRandomizedRetryStrategy adds randomized to exponential retryStrategy.
func ExponentialRandomizedRetryStrategy() RetryStrategy {
randSource := newRandSource()
return func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
base := math.Pow(2, float64(attemptNum)) * float64(min)
randomized := randSource.Float64() * (base - float64(min))
sleep := time.Duration(base + randomized)
if sleep > max {
return max
}
return sleep
}
}
// newRandSource initializes a rand source with a mutex for concurrency safety.
func newRandSource() *rand.Rand {
return rand.New(rand.NewSource(time.Now().UnixNano()))
}