github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/backoff/backoff.go (about) 1 package backoff 2 3 import ( 4 "math" 5 "time" 6 7 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xrand" 8 ) 9 10 // Backoff is the interface that contains logic of delaying operation retry. 11 type Backoff interface { 12 // Delay returns mapping of i to Delay. 13 Delay(i int) time.Duration 14 } 15 16 // Default parameters used by Retry() functions within different sub packages. 17 const ( 18 fastSlot = 5 * time.Millisecond 19 slowSlot = 1 * time.Second 20 ) 21 22 var ( 23 Fast = New( 24 WithSlotDuration(fastSlot), 25 WithCeiling(6), 26 ) 27 Slow = New( 28 WithSlotDuration(slowSlot), 29 WithCeiling(6), 30 ) 31 ) 32 33 var _ Backoff = (*logBackoff)(nil) 34 35 // logBackoff contains logarithmic Backoff policy. 36 type logBackoff struct { 37 // slotDuration is a size of a single time slot used in Backoff Delay 38 // calculation. 39 // If slotDuration is less or equal to zero, then the time.Second value is 40 // used. 41 slotDuration time.Duration 42 43 // ceiling is a maximum degree of Backoff Delay growth. 44 // If ceiling is less or equal to zero, then the default ceiling of 1 is 45 // used. 46 ceiling uint 47 48 // jitterLimit controls fixed and random portions of Backoff Delay. 49 // Its value can be in range [0, 1]. 50 // If jitterLimit is non zero, then the Backoff Delay will be equal to (F + R), 51 // where F is a result of multiplication of this value and calculated Delay 52 // duration D; and R is a random sized part from [0,(D - F)]. 53 jitterLimit float64 54 55 // generator of jitter 56 r xrand.Rand 57 } 58 59 type option func(b *logBackoff) 60 61 func WithSlotDuration(slotDuration time.Duration) option { 62 return func(b *logBackoff) { 63 b.slotDuration = slotDuration 64 } 65 } 66 67 func WithCeiling(ceiling uint) option { 68 return func(b *logBackoff) { 69 b.ceiling = ceiling 70 } 71 } 72 73 func WithJitterLimit(jitterLimit float64) option { 74 return func(b *logBackoff) { 75 b.jitterLimit = jitterLimit 76 } 77 } 78 79 func WithSeed(seed int64) option { 80 return func(b *logBackoff) { 81 b.r = xrand.New(xrand.WithLock(), xrand.WithSeed(seed)) 82 } 83 } 84 85 func New(opts ...option) logBackoff { 86 b := logBackoff{ 87 r: xrand.New(xrand.WithLock()), 88 } 89 for _, o := range opts { 90 if o != nil { 91 o(&b) 92 } 93 } 94 95 return b 96 } 97 98 // Delay returns mapping of i to Delay. 99 func (b logBackoff) Delay(i int) time.Duration { 100 s := b.slotDuration 101 if s <= 0 { 102 s = time.Second 103 } 104 n := 1 << min(uint(i), max(1, b.ceiling)) 105 d := s * time.Duration(n) 106 f := time.Duration(math.Min(1, math.Abs(b.jitterLimit)) * float64(d)) 107 if f == d { 108 return f 109 } 110 111 return f + time.Duration(b.r.Int64(int64(d-f)+1)) 112 } 113 114 func min(a, b uint) uint { 115 if a < b { 116 return a 117 } 118 119 return b 120 } 121 122 func max(a, b uint) uint { 123 if a > b { 124 return a 125 } 126 127 return b 128 }