gitee.com/gricks/utils@v1.0.8/backoff/backoff.go (about)

     1  package backoff
     2  
     3  import (
     4  	"math/rand"
     5  	"sync"
     6  	"time"
     7  )
     8  
     9  var (
    10  	r  = rand.New(rand.NewSource(time.Now().UnixNano()))
    11  	mu sync.Mutex
    12  )
    13  
    14  func rfloat64() float64 {
    15  	mu.Lock()
    16  	v := r.Float64()
    17  	mu.Unlock()
    18  	return v
    19  }
    20  
    21  // Strategy defines the methodology for backing off
    22  type Strategy interface {
    23  	Backoff(retries int) time.Duration
    24  }
    25  
    26  var DefaultStrategy = &Exponential{
    27  	BaseDelay:  1.0 * time.Second,
    28  	Multiplier: 1.6,
    29  	Jitter:     0.2,
    30  	MaxDelay:   120 * time.Second,
    31  }
    32  
    33  type Exponential struct {
    34  	// BaseDelay is the amount of time to backoff after the first failure.
    35  	BaseDelay time.Duration
    36  	// Multiplier is the factor with which to multiply backoffs after a
    37  	// failed retry. Should ideally be greater than 1.
    38  	Multiplier float64
    39  	// Jitter is the factor with which backoffs are randomized.
    40  	Jitter float64
    41  	// MaxDelay is the upper bound of backoff delay.
    42  	MaxDelay time.Duration
    43  }
    44  
    45  func (e Exponential) Backoff(retries int) time.Duration {
    46  	if retries == 0 {
    47  		return e.BaseDelay
    48  	}
    49  	backoff, max := float64(e.BaseDelay), float64(e.MaxDelay)
    50  	for backoff < max && retries > 0 {
    51  		backoff *= e.Multiplier
    52  		retries--
    53  	}
    54  	if backoff > max {
    55  		backoff = max
    56  	}
    57  	// Randomize backoff delays so that if a cluster of requests start at
    58  	// the same time, they won't operate in lockstep.
    59  	backoff *= 1 + e.Jitter*(rfloat64()*2-1)
    60  	if backoff < 0 {
    61  		return 0
    62  	}
    63  	return time.Duration(backoff)
    64  }