github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zutil/retry.go (about) 1 package zutil 2 3 import ( 4 "math/rand" 5 "time" 6 ) 7 8 type RetryConf struct { 9 // maxRetry is the maximum number of retries 10 maxRetry int 11 // Interval is the interval between retries 12 Interval time.Duration 13 // MaxRetryInterval is the maximum interval between retries 14 MaxRetryInterval time.Duration 15 // Timeout is the timeout of the entire retry 16 Timeout time.Duration 17 // BackOffDelay is whether to increase the interval between retries 18 BackOffDelay bool 19 } 20 21 // DoRetry is a general retry function 22 func DoRetry(sum int, fn func() bool, opt ...func(*RetryConf)) (ok bool) { 23 o := RetryConf{ 24 maxRetry: sum, 25 Interval: time.Second, 26 MaxRetryInterval: time.Minute, 27 } 28 for i := range opt { 29 opt[i](&o) 30 } 31 32 ok = fn() 33 if ok { 34 return 35 } 36 37 if o.maxRetry == 0 { 38 return false 39 } 40 41 i, now := 1, time.Now() 42 for ; ; i++ { 43 if o.maxRetry > 0 && i > o.maxRetry { 44 break 45 } 46 47 if o.Timeout > 0 && time.Since(now) > o.Timeout { 48 break 49 } 50 51 ok = fn() 52 if ok { 53 break 54 } 55 56 var interval time.Duration 57 if o.BackOffDelay { 58 interval = BackOffDelay(i, o.MaxRetryInterval) 59 } else { 60 interval = o.Interval 61 } 62 63 time.Sleep(interval) 64 } 65 66 return 67 } 68 69 func BackOffDelay(attempt int, maxRetryInterval time.Duration) time.Duration { 70 attempt = attempt - 1 71 if attempt < 0 { 72 return 0 73 } 74 75 retryFactor := 1 << uint(attempt) 76 jitter := rand.Float64() 77 waitDuration := time.Duration(retryFactor) * time.Second 78 waitDuration = waitDuration + time.Duration(jitter*float64(waitDuration)) 79 80 if waitDuration > maxRetryInterval { 81 return maxRetryInterval 82 } 83 84 return waitDuration 85 }