-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_test.go
More file actions
159 lines (145 loc) · 3.87 KB
/
Copy pathexample_test.go
File metadata and controls
159 lines (145 loc) · 3.87 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package retry_test
import (
"context"
"errors"
"fmt"
"time"
"lowbit.dev/retry"
)
// Example demonstrates the most common pattern: exponential back-off with a
// hard limit on total attempts.
func Example() {
ctx := context.Background()
err := retry.Do(ctx, retry.MaxAttempts(5, retry.Exponential(100*time.Millisecond, 30*time.Second)), func() error {
// replace with a real network call, database query, etc.
return nil
})
if err != nil {
fmt.Println("all attempts failed:", err)
}
}
// ExampleDo demonstrates retrying a function until it succeeds.
func ExampleDo() {
calls := 0
err := retry.Do(context.Background(), retry.MaxAttempts(5, retry.Constant(0)), func() error {
calls++
if calls < 3 {
return errors.New("transient error")
}
return nil
})
fmt.Println(err)
fmt.Println("calls:", calls)
// Output:
// <nil>
// calls: 3
}
// ExampleDo_doNotRetry shows that wrapping ErrDoNotRetry stops the loop
// immediately without consulting the strategy.
func ExampleDo_doNotRetry() {
calls := 0
err := retry.Do(context.Background(), retry.MaxAttempts(5, retry.Constant(0)), func() error {
calls++
return fmt.Errorf("permanent failure: %w", retry.ErrDoNotRetry)
})
fmt.Println(errors.Is(err, retry.ErrDoNotRetry))
fmt.Println("calls:", calls)
// Output:
// true
// calls: 1
}
// ExampleDo_limitExceeded shows that exhausting the strategy wraps the last
// error with ErrRetryLimitExceeded.
func ExampleDo_limitExceeded() {
calls := 0
err := retry.Do(context.Background(), retry.MaxAttempts(3, retry.Constant(0)), func() error {
calls++
return errors.New("always fails")
})
fmt.Println(errors.Is(err, retry.ErrRetryLimitExceeded))
fmt.Println("calls:", calls)
// Output:
// true
// calls: 3
}
// ExampleStrategy_Do shows calling Do as a method on a Strategy value.
func ExampleStrategy_Do() {
p := retry.MaxAttempts(3, retry.Constant(0))
calls := 0
err := p.Do(context.Background(), func() error {
calls++
return errors.New("fail")
})
fmt.Println(errors.Is(err, retry.ErrRetryLimitExceeded))
fmt.Println("calls:", calls)
// Output:
// true
// calls: 3
}
// ExampleExponential shows composition of Exponential with MaxAttempts.
// No Output: the jitter-based delays are non-deterministic.
func ExampleExponential() {
strategy := retry.MaxAttempts(5, retry.Exponential(100*time.Millisecond, 30*time.Second))
_ = strategy
}
// ExampleConstant shows that every retry waits the same duration.
func ExampleConstant() {
p := retry.Constant(500 * time.Millisecond)
fmt.Println(p(1))
fmt.Println(p(2))
fmt.Println(p(3))
// Output:
// 500ms
// 500ms
// 500ms
}
// ExampleLinear shows that the wait grows linearly: base × attempt.
func ExampleLinear() {
p := retry.Linear(100 * time.Millisecond)
fmt.Println(p(1))
fmt.Println(p(2))
fmt.Println(p(3))
// Output:
// 100ms
// 200ms
// 300ms
}
// ExampleMaxAttempts shows that the wrapped strategy returns -1 once n calls
// have been made, signalling Do to stop retrying.
func ExampleMaxAttempts() {
p := retry.MaxAttempts(3, retry.Constant(0))
fmt.Println(p(1)) // within limit
fmt.Println(p(2)) // within limit
fmt.Println(p(3)) // limit reached
// Output:
// 0s
// 0s
// -1ns
}
// ExampleNever shows that the strategy stops after the very first failure.
func ExampleNever() {
calls := 0
err := retry.Do(context.Background(), retry.Never, func() error {
calls++
return errors.New("fail")
})
fmt.Println(errors.Is(err, retry.ErrRetryLimitExceeded))
fmt.Println("calls:", calls)
// Output:
// true
// calls: 1
}
// ExampleAlways shows Always retrying immediately; compose with MaxAttempts
// to add an upper bound.
func ExampleAlways() {
calls := 0
err := retry.Do(context.Background(), retry.MaxAttempts(3, retry.Always), func() error {
calls++
return errors.New("fail")
})
fmt.Println(errors.Is(err, retry.ErrRetryLimitExceeded))
fmt.Println("calls:", calls)
// Output:
// true
// calls: 3
}