github.com/xmplusdev/xray-core@v1.8.10/common/retry/retry.go (about)

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