| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 | package retry // import "v2ray.com/core/common/retry"//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg retry -path Retryimport (	"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		},	}}
 |