1/*
2 *
3 * Copyright 2017 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package grpc
20
21import (
22	"math/rand"
23	"time"
24)
25
26// DefaultBackoffConfig uses values specified for backoff in
27// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
28var DefaultBackoffConfig = BackoffConfig{
29	MaxDelay:  120 * time.Second,
30	baseDelay: 1.0 * time.Second,
31	factor:    1.6,
32	jitter:    0.2,
33}
34
35// backoffStrategy defines the methodology for backing off after a grpc
36// connection failure.
37//
38// This is unexported until the gRPC project decides whether or not to allow
39// alternative backoff strategies. Once a decision is made, this type and its
40// method may be exported.
41type backoffStrategy interface {
42	// backoff returns the amount of time to wait before the next retry given
43	// the number of consecutive failures.
44	backoff(retries int) time.Duration
45}
46
47// BackoffConfig defines the parameters for the default gRPC backoff strategy.
48type BackoffConfig struct {
49	// MaxDelay is the upper bound of backoff delay.
50	MaxDelay time.Duration
51
52	// TODO(stevvooe): The following fields are not exported, as allowing
53	// changes would violate the current gRPC specification for backoff. If
54	// gRPC decides to allow more interesting backoff strategies, these fields
55	// may be opened up in the future.
56
57	// baseDelay is the amount of time to wait before retrying after the first
58	// failure.
59	baseDelay time.Duration
60
61	// factor is applied to the backoff after each retry.
62	factor float64
63
64	// jitter provides a range to randomize backoff delays.
65	jitter float64
66}
67
68func setDefaults(bc *BackoffConfig) {
69	md := bc.MaxDelay
70	*bc = DefaultBackoffConfig
71
72	if md > 0 {
73		bc.MaxDelay = md
74	}
75}
76
77func (bc BackoffConfig) backoff(retries int) time.Duration {
78	if retries == 0 {
79		return bc.baseDelay
80	}
81	backoff, max := float64(bc.baseDelay), float64(bc.MaxDelay)
82	for backoff < max && retries > 0 {
83		backoff *= bc.factor
84		retries--
85	}
86	if backoff > max {
87		backoff = max
88	}
89	// Randomize backoff delays so that if a cluster of requests start at
90	// the same time, they won't operate in lockstep.
91	backoff *= 1 + bc.jitter*(rand.Float64()*2-1)
92	if backoff < 0 {
93		return 0
94	}
95	return time.Duration(backoff)
96}
97