github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/dlock/retry.go (about) 1 package dlock 2 3 import ( 4 randv2 "math/rand/v2" 5 "sync/atomic" 6 "time" 7 ) 8 9 type linearBackoff time.Duration 10 11 func (backoff linearBackoff) Next() time.Duration { 12 return time.Duration(backoff) 13 } 14 15 func EndlessRetry(backoff time.Duration) RetryStrategy { 16 return linearBackoff(backoff) 17 } 18 19 func NoRetry() RetryStrategy { 20 return linearBackoff(0) 21 } 22 23 type limitedRetry struct { 24 strategy RetryStrategy 25 count int64 26 maxCount int64 27 } 28 29 func (retry *limitedRetry) Next() time.Duration { 30 if atomic.LoadInt64(&retry.count) >= retry.maxCount { 31 return 0 32 } 33 atomic.AddInt64(&retry.count, 1) 34 return retry.strategy.Next() 35 } 36 37 func LimitedRetry(backoff time.Duration, maxCount int64) RetryStrategy { 38 if backoff.Milliseconds() <= 0 { 39 return NoRetry() 40 } 41 return &limitedRetry{ 42 strategy: ExponentialBackoffRetry( 43 maxCount, 44 backoff, 45 0, 46 1.0, 47 0.1, 48 ), 49 maxCount: maxCount, 50 } 51 } 52 53 type exponentialBackoff struct { 54 duration time.Duration 55 factor float64 56 jitter float64 57 steps int64 58 cap time.Duration 59 } 60 61 func (backoff *exponentialBackoff) Next() time.Duration { 62 if atomic.LoadInt64(&backoff.steps) < 1 { 63 return NoRetry().Next() 64 } 65 atomic.AddInt64(&backoff.steps, -1) 66 duration := backoff.duration 67 if backoff.factor != 0 { 68 backoff.duration = time.Duration(float64(backoff.duration) * backoff.factor) 69 if backoff.cap > 0 && backoff.duration > backoff.cap { 70 backoff.duration = backoff.cap 71 atomic.SwapInt64(&backoff.steps, 0) 72 } 73 } 74 if backoff.jitter > 0 { 75 duration = duration + time.Duration(randv2.Float64()*backoff.jitter*float64(duration)) 76 } 77 return duration 78 } 79 80 func ExponentialBackoffRetry(maxSteps int64, initBackoff, maxBackoff time.Duration, backoffFactor, jitter float64) RetryStrategy { 81 return &exponentialBackoff{ 82 cap: maxBackoff, 83 duration: initBackoff, 84 factor: backoffFactor, 85 jitter: jitter, 86 steps: maxSteps, 87 } 88 } 89 90 func DefaultExponentialBackoffRetry() RetryStrategy { 91 return ExponentialBackoffRetry( 92 5, 93 10*time.Millisecond, 94 0, 95 1.0, 96 0.1, 97 ) 98 }