Skip to content

Commit e436cb1

Browse files
committed
breaking: panic instead of returning an error negative bases
1 parent 2ee2801 commit e436cb1

9 files changed

+96
-159
lines changed

README.md

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,13 @@ func main() {
4545
}
4646

4747
ctx := context.Background()
48-
err := retry.Fibonacci(ctx, 1*time.Second, func(ctx context.Context) error {
48+
if err := retry.Fibonacci(ctx, 1*time.Second, func(ctx context.Context) error {
4949
if err := db.PingContext(ctx); err != nil {
5050
// This marks the error as retryable
5151
return retry.RetryableError(err)
5252
}
5353
return nil
54-
})
55-
if err != nil {
54+
}); err != nil {
5655
log.Fatal(err)
5756
}
5857
}
@@ -121,10 +120,7 @@ To reduce the changes of a thundering herd, add random jitter to the returned
121120
value.
122121

123122
```golang
124-
b, err := NewFibonacci(1 * time.Second)
125-
if err != nil {
126-
// handle err
127-
}
123+
b := NewFibonacci(1 * time.Second)
128124

129125
// Return the next value, +/- 500ms
130126
b = WithJitter(500*time.Millisecond, b)
@@ -139,10 +135,7 @@ To terminate a retry, specify the maximum number of _retries_. Note this
139135
is _retries_, not _attempts_. Attempts is retries + 1.
140136

141137
```golang
142-
b, err := NewFibonacci(1 * time.Second)
143-
if err != nil {
144-
// handle err
145-
}
138+
b := NewFibonacci(1 * time.Second)
146139

147140
// Stop after 4 retries, when the 5th attempt has failed. In this example, the worst case elapsed
148141
// time would be 1s + 1s + 2s + 3s = 7s.
@@ -154,10 +147,7 @@ b = WithMaxRetries(4, b)
154147
To ensure an individual calculated duration never exceeds a value, use a cap:
155148

156149
```golang
157-
b, err := NewFibonacci(1 * time.Second)
158-
if err != nil {
159-
// handle err
160-
}
150+
b := NewFibonacci(1 * time.Second)
161151

162152
// Ensure the maximum value is 2s. In this example, the sleep values would be
163153
// 1s, 1s, 2s, 2s, 2s, 2s...
@@ -169,10 +159,7 @@ b = WithCappedDuration(2 * time.Second, b)
169159
For a best-effort limit on the total execution time, specify a max duration:
170160

171161
```golang
172-
b, err := NewFibonacci(1 * time.Second)
173-
if err != nil {
174-
// handle err
175-
}
162+
b := NewFibonacci(1 * time.Second)
176163

177164
// Ensure the maximum total retry time is 5s.
178165
b = WithMaxDuration(5 * time.Second, b)

backoff_constant.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,24 @@ package retry
22

33
import (
44
"context"
5-
"fmt"
65
"time"
76
)
87

9-
// Constant is a wrapper around Retry that uses a constant backoff.
8+
// Constant is a wrapper around Retry that uses a constant backoff. It panics if
9+
// the given base is less than zero.
1010
func Constant(ctx context.Context, t time.Duration, f RetryFunc) error {
11-
b, err := NewConstant(t)
12-
if err != nil {
13-
return err
14-
}
15-
return Do(ctx, b, f)
11+
return Do(ctx, NewConstant(t), f)
1612
}
1713

1814
// NewConstant creates a new constant backoff using the value t. The wait time
19-
// is the provided constant value.
20-
func NewConstant(t time.Duration) (Backoff, error) {
15+
// is the provided constant value. It panics if the given base is less than
16+
// zero.
17+
func NewConstant(t time.Duration) Backoff {
2118
if t <= 0 {
22-
return nil, fmt.Errorf("t must be greater than 0")
19+
panic("t must be greater than 0")
2320
}
2421

2522
return BackoffFunc(func() (time.Duration, bool) {
2623
return t, false
27-
}), nil
24+
})
2825
}

backoff_constant_test.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
package retry
1+
package retry_test
22

33
import (
44
"fmt"
55
"reflect"
66
"sort"
77
"testing"
88
"time"
9+
10+
"github.com/sethvargo/go-retry"
911
)
1012

1113
func TestConstantBackoff(t *testing.T) {
@@ -16,12 +18,7 @@ func TestConstantBackoff(t *testing.T) {
1618
base time.Duration
1719
tries int
1820
exp []time.Duration
19-
err bool
2021
}{
21-
{
22-
name: "zero",
23-
err: true,
24-
},
2522
{
2623
name: "single",
2724
base: 1 * time.Nanosecond,
@@ -71,13 +68,7 @@ func TestConstantBackoff(t *testing.T) {
7168
t.Run(tc.name, func(t *testing.T) {
7269
t.Parallel()
7370

74-
b, err := NewConstant(tc.base)
75-
if (err != nil) != tc.err {
76-
t.Fatal(err)
77-
}
78-
if b == nil {
79-
return
80-
}
71+
b := retry.NewConstant(tc.base)
8172

8273
resultsCh := make(chan time.Duration, tc.tries)
8374
for i := 0; i < tc.tries; i++ {
@@ -108,10 +99,7 @@ func TestConstantBackoff(t *testing.T) {
10899
}
109100

110101
func ExampleNewConstant() {
111-
b, err := NewConstant(1 * time.Second)
112-
if err != nil {
113-
// handle err
114-
}
102+
b := retry.NewConstant(1 * time.Second)
115103

116104
for i := 0; i < 5; i++ {
117105
val, _ := b.Next()

backoff_exponential.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package retry
22

33
import (
44
"context"
5-
"fmt"
65
"sync/atomic"
76
"time"
87
)
@@ -14,27 +13,23 @@ type exponentialBackoff struct {
1413

1514
// Exponential is a wrapper around Retry that uses an exponential backoff. It's
1615
// very efficient, but does not check for overflow, so ensure you bound the
17-
// retry.
16+
// retry. It panics if the given base is less than zero.
1817
func Exponential(ctx context.Context, base time.Duration, f RetryFunc) error {
19-
b, err := NewExponential(base)
20-
if err != nil {
21-
return err
22-
}
23-
return Do(ctx, b, f)
18+
return Do(ctx, NewExponential(base), f)
2419
}
2520

2621
// NewExponential creates a new exponential backoff using the starting value of
2722
// base and doubling on each failure (1, 2, 4, 8, 16, 32, 64...), up to max.
2823
// It's very efficient, but does not check for overflow, so ensure you bound the
29-
// retry.
30-
func NewExponential(base time.Duration) (Backoff, error) {
24+
// retry. It panics if the given base is less than 0.
25+
func NewExponential(base time.Duration) Backoff {
3126
if base <= 0 {
32-
return nil, fmt.Errorf("base must be greater than 0")
27+
panic("base must be greater than 0")
3328
}
3429

3530
return &exponentialBackoff{
3631
base: base,
37-
}, nil
32+
}
3833
}
3934

4035
// Next implements Backoff. It is safe for concurrent use.

backoff_exponential_test.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
package retry
1+
package retry_test
22

33
import (
44
"fmt"
55
"reflect"
66
"sort"
77
"testing"
88
"time"
9+
10+
"github.com/sethvargo/go-retry"
911
)
1012

1113
func TestExponentialBackoff(t *testing.T) {
@@ -16,12 +18,7 @@ func TestExponentialBackoff(t *testing.T) {
1618
base time.Duration
1719
tries int
1820
exp []time.Duration
19-
err bool
2021
}{
21-
{
22-
name: "zero",
23-
err: true,
24-
},
2522
{
2623
name: "single",
2724
base: 1 * time.Nanosecond,
@@ -59,13 +56,7 @@ func TestExponentialBackoff(t *testing.T) {
5956
t.Run(tc.name, func(t *testing.T) {
6057
t.Parallel()
6158

62-
b, err := NewExponential(tc.base)
63-
if (err != nil) != tc.err {
64-
t.Fatal(err)
65-
}
66-
if b == nil {
67-
return
68-
}
59+
b := retry.NewExponential(tc.base)
6960

7061
resultsCh := make(chan time.Duration, tc.tries)
7162
for i := 0; i < tc.tries; i++ {
@@ -96,10 +87,7 @@ func TestExponentialBackoff(t *testing.T) {
9687
}
9788

9889
func ExampleNewExponential() {
99-
b, err := NewExponential(1 * time.Second)
100-
if err != nil {
101-
// handle err
102-
}
90+
b := retry.NewExponential(1 * time.Second)
10391

10492
for i := 0; i < 5; i++ {
10593
val, _ := b.Next()

backoff_fibonacci.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package retry
22

33
import (
44
"context"
5-
"fmt"
65
"sync/atomic"
76
"time"
87
"unsafe"
@@ -14,26 +13,24 @@ type fibonacciBackoff struct {
1413
state unsafe.Pointer
1514
}
1615

17-
// Fibonacci is a wrapper around Retry that uses a Fibonacci backoff.
16+
// Fibonacci is a wrapper around Retry that uses a Fibonacci backoff. It panics
17+
// if the given base is less than zero.
1818
func Fibonacci(ctx context.Context, base time.Duration, f RetryFunc) error {
19-
b, err := NewFibonacci(base)
20-
if err != nil {
21-
return err
22-
}
23-
return Do(ctx, b, f)
19+
return Do(ctx, NewFibonacci(base), f)
2420
}
2521

2622
// NewFibonacci creates a new Fibonacci backoff using the starting value of
2723
// base. The wait time is the sum of the previous two wait times on each failed
28-
// attempt (1, 1, 2, 3, 5, 8, 13...).
29-
func NewFibonacci(base time.Duration) (Backoff, error) {
24+
// attempt (1, 1, 2, 3, 5, 8, 13...). It panics if the given base is less than
25+
// zero.
26+
func NewFibonacci(base time.Duration) Backoff {
3027
if base <= 0 {
31-
return nil, fmt.Errorf("base must be greater than 0")
28+
panic("base must be greater than 0")
3229
}
3330

3431
return &fibonacciBackoff{
3532
state: unsafe.Pointer(&state{0, base}),
36-
}, nil
33+
}
3734
}
3835

3936
// Next implements Backoff. It is safe for concurrent use.

backoff_fibonacci_test.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
package retry
1+
package retry_test
22

33
import (
44
"fmt"
55
"reflect"
66
"sort"
77
"testing"
88
"time"
9+
10+
"github.com/sethvargo/go-retry"
911
)
1012

1113
func TestFibonacciBackoff(t *testing.T) {
@@ -16,12 +18,7 @@ func TestFibonacciBackoff(t *testing.T) {
1618
base time.Duration
1719
tries int
1820
exp []time.Duration
19-
err bool
2021
}{
21-
{
22-
name: "zero",
23-
err: true,
24-
},
2522
{
2623
name: "single",
2724
base: 1 * time.Nanosecond,
@@ -71,13 +68,7 @@ func TestFibonacciBackoff(t *testing.T) {
7168
t.Run(tc.name, func(t *testing.T) {
7269
t.Parallel()
7370

74-
b, err := NewFibonacci(tc.base)
75-
if (err != nil) != tc.err {
76-
t.Fatal(err)
77-
}
78-
if b == nil {
79-
return
80-
}
71+
b := retry.NewFibonacci(tc.base)
8172

8273
resultsCh := make(chan time.Duration, tc.tries)
8374
for i := 0; i < tc.tries; i++ {
@@ -108,10 +99,7 @@ func TestFibonacciBackoff(t *testing.T) {
10899
}
109100

110101
func ExampleNewFibonacci() {
111-
b, err := NewFibonacci(1 * time.Second)
112-
if err != nil {
113-
// handle err
114-
}
102+
b := retry.NewFibonacci(1 * time.Second)
115103

116104
for i := 0; i < 5; i++ {
117105
val, _ := b.Next()

0 commit comments

Comments
 (0)