github.com/msales/pkg/v3@v3.24.0/retry/retry.go (about)

     1  package retry
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  )
     7  
     8  // Policy determines how Run retries the function.
     9  type Policy interface {
    10  	Next() (time.Duration, bool)
    11  }
    12  
    13  type exponentialPolicy struct {
    14  	attempts int
    15  	sleep    time.Duration
    16  }
    17  
    18  // ExponentialPolicy retires with an exponential growth in sleep.
    19  func ExponentialPolicy(attempts int, sleep time.Duration) Policy {
    20  	return &exponentialPolicy{
    21  		attempts: attempts,
    22  		sleep:    sleep,
    23  	}
    24  }
    25  
    26  func (p *exponentialPolicy) Next() (time.Duration, bool) {
    27  	p.attempts--
    28  	if p.attempts <= 0 {
    29  		return 0, false
    30  	}
    31  
    32  	defer func() {
    33  		p.sleep *= 2
    34  	}()
    35  
    36  	return p.sleep, true
    37  }
    38  
    39  // Run executes the function while the Policy allows
    40  // until it returns nil or Stop.
    41  func Run(p Policy, fn func() error) error {
    42  	if p == nil {
    43  		return errors.New("policy must not be nil")
    44  	}
    45  
    46  	if err := fn(); err != nil {
    47  		if s, ok := err.(stop); ok {
    48  			return s.error
    49  		}
    50  
    51  		if sleep, ok := p.Next(); ok {
    52  			time.Sleep(sleep)
    53  			Run(p, fn)
    54  		}
    55  
    56  		return err
    57  	}
    58  
    59  	return nil
    60  }
    61  
    62  type stop struct {
    63  	error
    64  }
    65  
    66  // Stop wraps an error and stops retrying.
    67  func Stop(err error) error {
    68  	return stop{err}
    69  }