@@ -5,6 +5,7 @@ package retry
5
5
6
6
import (
7
7
"context"
8
+ "math"
8
9
"math/rand"
9
10
"time"
10
11
)
@@ -24,8 +25,15 @@ func jitterUp(duration time.Duration, jitter float64) time.Duration {
24
25
return time .Duration (float64 (duration ) * (1 + multiplier ))
25
26
}
26
27
27
- // exponentBase2 computes 2^(a-1) where a >= 1. If a is 0, the result is 0.
28
+ // exponentBase2 computes 2^(a-1) where a >= 1. If a is 0, the result is 1.
29
+ // if a is greater than 62, the result is 2^62 to avoid overflowing int64
28
30
func exponentBase2 (a uint ) uint {
31
+ if a == 0 {
32
+ return 1
33
+ }
34
+ if a > 62 {
35
+ return 1 << 62
36
+ }
29
37
return (1 << a ) >> 1
30
38
}
31
39
@@ -50,6 +58,31 @@ func BackoffExponential(scalar time.Duration) BackoffFunc {
50
58
// BackoffExponential does, but adds jitter.
51
59
func BackoffExponentialWithJitter (scalar time.Duration , jitterFraction float64 ) BackoffFunc {
52
60
return func (ctx context.Context , attempt uint ) time.Duration {
61
+ exp := exponentBase2 (attempt )
62
+ dur := scalar * time .Duration (exp )
63
+ // Check for overflow in duration multiplication
64
+ if exp != 0 && dur / scalar != time .Duration (exp ) {
65
+ return time .Duration (math .MaxInt64 )
66
+ }
53
67
return jitterUp (scalar * time .Duration (exponentBase2 (attempt )), jitterFraction )
54
68
}
55
69
}
70
+
71
+ func BackoffExponentialWithJitterBounded (scalar time.Duration , jitterFrac float64 , maxBound time.Duration ) BackoffFunc {
72
+ return func (ctx context.Context , attempt uint ) time.Duration {
73
+ exp := exponentBase2 (attempt )
74
+ dur := scalar * time .Duration (exp )
75
+ // Check for overflow in duration multiplication
76
+ if exp != 0 && dur / scalar != time .Duration (exp ) {
77
+ return maxBound
78
+ }
79
+ // Apply random jitter between -jitterFrac and +jitterFrac
80
+ jitter := 1 + jitterFrac * (rand .Float64 ()* 2 - 1 )
81
+ jitteredDuration := time .Duration (float64 (dur ) * jitter )
82
+ // Check for overflow in jitter multiplication
83
+ if float64 (dur )* jitter > float64 (math .MaxInt64 ) {
84
+ return maxBound
85
+ }
86
+ return min (jitteredDuration , maxBound )
87
+ }
88
+ }
0 commit comments