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  }