Hunter0x7c7
2022-08-11 b8230139fb40edea387617b6accd8371e37eda58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package retry
 
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
 
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
        },
    }
}