| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 | 
							- package retry
 
- //go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg retry -path Retry
 
- import (
 
- 	"time"
 
- )
 
- var (
 
- 	ErrRetryFailed = newError("all retry attempts failed")
 
- )
 
- // Strategy is a way to retry on a specific function.
 
- type Strategy interface {
 
- 	// On performs a retry on a specific function, until it doesn't return any error.
 
- 	On(func() error) error
 
- }
 
- type retryer struct {
 
- 	totalAttempt int
 
- 	nextDelay    func() uint32
 
- }
 
- // On implements Strategy.On.
 
- func (r *retryer) On(method func() error) error {
 
- 	attempt := 0
 
- 	accumulatedError := make([]error, 0, r.totalAttempt)
 
- 	for attempt < r.totalAttempt {
 
- 		err := method()
 
- 		if err == nil {
 
- 			return nil
 
- 		}
 
- 		numErrors := len(accumulatedError)
 
- 		if numErrors == 0 || err.Error() != accumulatedError[numErrors-1].Error() {
 
- 			accumulatedError = append(accumulatedError, err)
 
- 		}
 
- 		delay := r.nextDelay()
 
- 		time.Sleep(time.Duration(delay) * time.Millisecond)
 
- 		attempt++
 
- 	}
 
- 	return newError(accumulatedError).Base(ErrRetryFailed)
 
- }
 
- // Timed returns a retry strategy with fixed interval.
 
- func Timed(attempts int, delay uint32) Strategy {
 
- 	return &retryer{
 
- 		totalAttempt: attempts,
 
- 		nextDelay: func() uint32 {
 
- 			return delay
 
- 		},
 
- 	}
 
- }
 
- func ExponentialBackoff(attempts int, delay uint32) Strategy {
 
- 	nextDelay := uint32(0)
 
- 	return &retryer{
 
- 		totalAttempt: attempts,
 
- 		nextDelay: func() uint32 {
 
- 			r := nextDelay
 
- 			nextDelay += delay
 
- 			return r
 
- 		},
 
- 	}
 
- }
 
 
  |