Skip to content

Commit 15ea740

Browse files
polyfloyddomgreen
authored andcommitted
Add exponential backoff functions (#152)
* Add exponential backoff functions * Move backoff exponent to backoffutils * Add an exampe for the exponential backoff
1 parent e9c5d96 commit 15ea740

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

retry/backoff.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,21 @@ func BackoffLinearWithJitter(waitBetween time.Duration, jitterFraction float64)
2424
return backoffutils.JitterUp(waitBetween, jitterFraction)
2525
}
2626
}
27+
28+
// BackoffExponential produces increasing intervals for each attempt.
29+
//
30+
// The scalar is multiplied times 2 raised to the current attempt. So the first
31+
// retry with a scalar of 100ms is 100ms, while the 5th attempt would be 3.2s.
32+
func BackoffExponential(scalar time.Duration) BackoffFunc {
33+
return func(attempt uint) time.Duration {
34+
return scalar * time.Duration(backoffutils.ExponentBase2(attempt))
35+
}
36+
}
37+
38+
// BackoffExponentialWithJitter creates an exponential backoff like
39+
// BackoffExponential does, but adds jitter.
40+
func BackoffExponentialWithJitter(scalar time.Duration, jitterFraction float64) BackoffFunc {
41+
return func(attempt uint) time.Duration {
42+
return backoffutils.JitterUp(scalar*time.Duration(backoffutils.ExponentBase2(attempt)), jitterFraction)
43+
}
44+
}

retry/examples_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ func Example_initializationWithOptions() {
4242
)
4343
}
4444

45+
// Example with an exponential backoff starting with 100ms.
46+
//
47+
// Each next interval is the previous interval multiplied by 2.
48+
func Example_initializationWithExponentialBackoff() {
49+
opts := []grpc_retry.CallOption{
50+
grpc_retry.WithBackoff(grpc_retry.BackoffExponential(100 * time.Millisecond)),
51+
}
52+
grpc.Dial("myservice.example.com",
53+
grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(opts...)),
54+
grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(opts...)),
55+
)
56+
}
57+
4558
// Simple example of an idempotent `ServerStream` call, that will be retried automatically 3 times.
4659
func Example_simpleCall() {
4760
client := pb_testproto.NewTestServiceClient(cc)

util/backoffutils/backoff.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,8 @@ func JitterUp(duration time.Duration, jitter float64) time.Duration {
2121
multiplier := jitter * (rand.Float64()*2 - 1)
2222
return time.Duration(float64(duration) * (1 + multiplier))
2323
}
24+
25+
// ExponentBase2 computes 2^(a-1) where a >= 1. If a is 0, the result is 0.
26+
func ExponentBase2(a uint) uint {
27+
return (1 << a) >> 1
28+
}

0 commit comments

Comments
 (0)