1# Retry
2
3[](https://pkg.go.dev/mod/github.com/sethvargo/go-retry)
4
5Retry is a Go library for facilitating retry logic and backoff. It's highly
6extensible with full control over how and when retries occur. You can also write
7your own custom backoff functions by implementing the Backoff interface.
8
9## Features
10
11- **Extensible** - Inspired by Go's built-in HTTP package, this Go backoff and
12 retry library is extensible via middleware. You can write custom backoff
13 functions or use a provided filter.
14
15- **Independent** - No external dependencies besides the Go standard library,
16 meaning it won't bloat your project.
17
18- **Concurrent** - Unless otherwise specified, everything is safe for concurrent
19 use.
20
21- **Context-aware** - Use native Go contexts to control cancellation.
22
23## Usage
24
25Here is an example use for connecting to a database using Go's `database/sql`
26package:
27
28```golang
29package main
30
31import (
32 "context"
33 "database/sql"
34 "log"
35 "time"
36
37 "github.com/sethvargo/go-retry"
38)
39
40func main() {
41 db, err := sql.Open("mysql", "...")
42 if err != nil {
43 log.Fatal(err)
44 }
45
46 ctx := context.Background()
47 if err := retry.Fibonacci(ctx, 1*time.Second, func(ctx context.Context) error {
48 if err := db.PingContext(ctx); err != nil {
49 // This marks the error as retryable
50 return retry.RetryableError(err)
51 }
52 return nil
53 }); err != nil {
54 log.Fatal(err)
55 }
56}
57```
58
59## Backoffs
60
61In addition to your own custom algorithms, there are built-in algorithms for
62backoff in the library.
63
64### Constant
65
66A very rudimentary backoff, just returns a constant value. Here is an example:
67
68```text
691s -> 1s -> 1s -> 1s -> 1s -> 1s
70```
71
72Usage:
73
74```golang
75NewConstant(1 * time.Second)
76```
77
78### Exponential
79
80Arguably the most common backoff, the next value is double the previous value.
81Here is an example:
82
83```text
841s -> 2s -> 4s -> 8s -> 16s -> 32s -> 64s
85```
86
87Usage:
88
89```golang
90NewExponential(1 * time.Second)
91```
92
93### Fibonacci
94
95The Fibonacci backoff uses the Fibonacci sequence to calculate the backoff. The
96next value is the sum of the current value and the previous value. This means
97retires happen quickly at first, but then gradually take slower, ideal for
98network-type issues. Here is an example:
99
100```text
1011s -> 1s -> 2s -> 3s -> 5s -> 8s -> 13s
102```
103
104Usage:
105
106```golang
107NewFibonacci(1 * time.Second)
108```
109
110## Modifiers (Middleware)
111
112The built-in backoff algorithms never terminate and have no caps or limits - you
113control their behavior with middleware. There's built-in middleware, but you can
114also write custom middleware.
115
116### Jitter
117
118To reduce the changes of a thundering herd, add random jitter to the returned
119value.
120
121```golang
122b := NewFibonacci(1 * time.Second)
123
124// Return the next value, +/- 500ms
125b = WithJitter(500*time.Millisecond, b)
126
127// Return the next value, +/- 5% of the result
128b = WithJitterPercent(5, b)
129```
130
131### MaxRetries
132
133To terminate a retry, specify the maximum number of _retries_. Note this
134is _retries_, not _attempts_. Attempts is retries + 1.
135
136```golang
137b := NewFibonacci(1 * time.Second)
138
139// Stop after 4 retries, when the 5th attempt has failed. In this example, the worst case elapsed
140// time would be 1s + 1s + 2s + 3s = 7s.
141b = WithMaxRetries(4, b)
142```
143
144### CappedDuration
145
146To ensure an individual calculated duration never exceeds a value, use a cap:
147
148```golang
149b := NewFibonacci(1 * time.Second)
150
151// Ensure the maximum value is 2s. In this example, the sleep values would be
152// 1s, 1s, 2s, 2s, 2s, 2s...
153b = WithCappedDuration(2 * time.Second, b)
154```
155
156### WithMaxDuration
157
158For a best-effort limit on the total execution time, specify a max duration:
159
160```golang
161b := NewFibonacci(1 * time.Second)
162
163// Ensure the maximum total retry time is 5s.
164b = WithMaxDuration(5 * time.Second, b)
165```
166
167## Benchmarks
168
169Here are benchmarks against some other popular Go backoff and retry libraries.
170You can run these benchmarks yourself via the `benchmark/` folder. Commas and
171spacing fixed for clarity.
172
173```text
174Benchmark/cenkalti-7 13,052,668 87.3 ns/op
175Benchmark/lestrrat-7 902,044 1,355 ns/op
176Benchmark/sethvargo-7 203,914,245 5.73 ns/op
177```
178
179## Notes and Caveats
180
181- Randomization uses `math/rand` seeded with the Unix timestamp instead of
182 `crypto/rand`.
183- Ordering of addition of multiple modifiers will make a difference.
184 For example; ensure you add `CappedDuration` before `WithMaxDuration`, otherwise it may early out too early.
185 Another example is you could add `Jitter` before or after capping depending on your desired outcome.