forked from galaxydi/go-loghub
-
Notifications
You must be signed in to change notification settings - Fork 113
/
retry.go
112 lines (104 loc) · 2.75 KB
/
retry.go
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package sls
import (
"golang.org/x/net/context"
"github.com/cenkalti/backoff"
"github.com/pkg/errors"
)
// Retry execute the input operation immediately at first,
// and do an exponential backoff retry when failed.
// The default max elapsed time is 15 minutes.
// The default retry intervals are shown below, in seconds.
// 1 0.5 [0.25, 0.75]
// 2 0.75 [0.375, 1.125]
// 3 1.125 [0.562, 1.687]
// 4 1.687 [0.8435, 2.53]
// 5 2.53 [1.265, 3.795]
// 6 3.795 [1.897, 5.692]
// 7 5.692 [2.846, 8.538]
// 8 8.538 [4.269, 12.807]
// 9 12.807 [6.403, 19.210]
// ...
// The signature of backoff.Operation is "func() error".
func Retry(ctx context.Context, o backoff.Operation) error {
return RetryWithBackOff(ctx, backoff.NewExponentialBackOff(), o)
}
// RetryWithBackOff ...
func RetryWithBackOff(ctx context.Context, b backoff.BackOff, o backoff.Operation) error {
ticker := backoff.NewTicker(b)
defer ticker.Stop()
var err error
for {
select {
case <-ctx.Done():
return errors.Wrapf(ctx.Err(), "stopped retrying err: %v", err)
default:
select {
case _, ok := <-ticker.C:
if !ok {
return err
}
err = o()
if err == nil {
return nil
}
case <-ctx.Done():
return errors.Wrapf(ctx.Err(), "stopped retrying err: %v", err)
}
}
}
}
// ConditionOperation : retry depends on the retured bool
type ConditionOperation func() (bool, error)
// RetryWithCondition ...
func RetryWithCondition(ctx context.Context, b backoff.BackOff, o ConditionOperation) error {
ticker := backoff.NewTicker(b)
defer ticker.Stop()
var err error
var needRetry bool
for {
select {
case <-ctx.Done():
return errors.Wrapf(ctx.Err(), "stopped retrying err: %v", err)
default:
select {
case _, ok := <-ticker.C:
if !ok {
return err
}
needRetry, err = o()
if !needRetry {
return err
}
case <-ctx.Done():
return errors.Wrapf(ctx.Err(), "stopped retrying err: %v", err)
}
}
}
}
// RetryWithAttempt ...
func RetryWithAttempt(ctx context.Context, maxAttempt int, o ConditionOperation) error {
b := backoff.NewExponentialBackOff()
ticker := backoff.NewTicker(b)
defer ticker.Stop()
var err error
var needRetry bool
for try := 0; try < maxAttempt; try++ {
// make sure we check ctx.Done() first
select {
case <-ctx.Done():
return errors.Wrapf(ctx.Err(), "stopped retrying err: %v", err)
default:
}
select {
case _, ok := <-ticker.C:
if !ok {
return err
}
needRetry, err = o()
if !needRetry {
return err
}
}
}
return err
}