github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/common/retry/retry.go (about)

     1  package retry // import "v2ray.com/core/common/retry"
     2  
     3  //go:generate go run v2ray.com/core/common/errors/errorgen
     4  
     5  import (
     6  	"time"
     7  )
     8  
     9  var (
    10  	ErrRetryFailed = newError("all retry attempts failed")
    11  )
    12  
    13  // Strategy is a way to retry on a specific function.
    14  type Strategy interface {
    15  	// On performs a retry on a specific function, until it doesn't return any error.
    16  	On(func() error) error
    17  }
    18  
    19  type retryer struct {
    20  	totalAttempt int
    21  	nextDelay    func() uint32
    22  }
    23  
    24  // On implements Strategy.On.
    25  func (r *retryer) On(method func() error) error {
    26  	attempt := 0
    27  	accumulatedError := make([]error, 0, r.totalAttempt)
    28  	for attempt < r.totalAttempt {
    29  		err := method()
    30  		if err == nil {
    31  			return nil
    32  		}
    33  		numErrors := len(accumulatedError)
    34  		if numErrors == 0 || err.Error() != accumulatedError[numErrors-1].Error() {
    35  			accumulatedError = append(accumulatedError, err)
    36  		}
    37  		delay := r.nextDelay()
    38  		time.Sleep(time.Duration(delay) * time.Millisecond)
    39  		attempt++
    40  	}
    41  	return newError(accumulatedError).Base(ErrRetryFailed)
    42  }
    43  
    44  // Timed returns a retry strategy with fixed interval.
    45  func Timed(attempts int, delay uint32) Strategy {
    46  	return &retryer{
    47  		totalAttempt: attempts,
    48  		nextDelay: func() uint32 {
    49  			return delay
    50  		},
    51  	}
    52  }
    53  
    54  func ExponentialBackoff(attempts int, delay uint32) Strategy {
    55  	nextDelay := uint32(0)
    56  	return &retryer{
    57  		totalAttempt: attempts,
    58  		nextDelay: func() uint32 {
    59  			r := nextDelay
    60  			nextDelay += delay
    61  			return r
    62  		},
    63  	}
    64  }