Skip to content

Commit

Permalink
Support for backoff params as defined in
Browse files Browse the repository at this point in the history
  • Loading branch information
easwars committed Aug 6, 2019
1 parent a8ef06a commit 452f9d8
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 58 deletions.
25 changes: 25 additions & 0 deletions backoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,37 @@ import (

// DefaultBackoffConfig uses values specified for backoff in
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
//
// Deprecated: use ConnectParams instead.
var DefaultBackoffConfig = BackoffConfig{
MaxDelay: 120 * time.Second,
}

// BackoffConfig defines the parameters for the default gRPC backoff strategy.
//
// Deprecated: use ConnectParams instead.
type BackoffConfig struct {
// MaxDelay is the upper bound of backoff delay.
MaxDelay time.Duration
}

// ConnectParams defines the parameters for connecting and retrying. Users
// are encouraged to use this instead of BackoffConfig.
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
//
// This API is EXPERIMENTAL.
type ConnectParams struct {
// BackoffBaseDelay is the amount of time to backoff after the first
// connection failure.
BackoffBaseDelay time.Duration
// BackoffMultiplier is the factor with which to multiply backoffs after a
// failed retry. Should ideally be greater than 1.
BackoffMultiplier float64
// BackoffJitter is the factor with which backoffs are randomized.
BackoffJitter float64
// BackoffMaxDelay is the upper bound of backoff delay.
BackoffMaxDelay time.Duration
// MinConnectTimeout is the minimum amount of time we are willing to give a
// connection to complete.
MinConnectTimeout time.Duration
}
8 changes: 3 additions & 5 deletions balancer/grpclb/grpclb.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,14 @@ const (
)

var (
// defaultBackoffConfig configures the backoff strategy that's used when the
// defaultBackoffStrategy configures the backoff strategy that's used when the
// init handshake in the RPC is unsuccessful. It's not for the clientconn
// reconnect backoff.
//
// It has the same value as the default grpc.DefaultBackoffConfig.
//
// TODO: make backoff configurable.
defaultBackoffConfig = backoff.Exponential{
MaxDelay: 120 * time.Second,
}
defaultBackoffStrategy = backoff.NewExponentialBuilder().Build()
errServerTerminatedConnection = errors.New("grpclb: failed to recv server list: server terminated connection")
)

Expand Down Expand Up @@ -155,7 +153,7 @@ func (b *lbBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) bal
scStates: make(map[balancer.SubConn]connectivity.State),
picker: &errPicker{err: balancer.ErrNoSubConnAvailable},
clientStats: newRPCStats(),
backoff: defaultBackoffConfig, // TODO: make backoff configurable.
backoff: defaultBackoffStrategy, // TODO: make backoff configurable.
}

var err error
Expand Down
4 changes: 1 addition & 3 deletions balancer/xds/lrs/lrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,7 @@ func NewStore(serviceName string) Store {
},
},
},
backoff: backoff.Exponential{
MaxDelay: 120 * time.Second,
},
backoff: backoff.NewExponentialBuilder().Build(),
lastReported: time.Now(),
}
}
Expand Down
9 changes: 3 additions & 6 deletions balancer/xds/xds_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@ const (
endpointRequired = "endpoints_required"
)

var (
defaultBackoffConfig = backoff.Exponential{
MaxDelay: 120 * time.Second,
}
)
var defaultBackoffStrategy = backoff.NewExponentialBuilder().Build()

// client is responsible for connecting to the specified traffic director, passing the received
// ADS response from the traffic director, and sending notification when communication with the
Expand Down Expand Up @@ -255,7 +251,8 @@ func newXDSClient(balancerName string, serviceName string, enableCDS bool, opts
newADS: newADS,
loseContact: loseContact,
cleanup: exitCleanup,
backoff: defaultBackoffConfig,
backoff: defaultBackoffStrategy,
loadStore: loadStore,
}

c.ctx, c.cancel = context.WithCancel(context.Background())
Expand Down
8 changes: 2 additions & 6 deletions clientconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ import (
)

const (
// minimum time to give a connection to complete
minConnectTimeout = 20 * time.Second
// must match grpclbName in grpclb/grpclb.go
grpclbName = "grpclb"
)
Expand Down Expand Up @@ -235,9 +233,7 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
}
}
if cc.dopts.bs == nil {
cc.dopts.bs = backoff.Exponential{
MaxDelay: DefaultBackoffConfig.MaxDelay,
}
cc.dopts.bs = backoff.NewExponentialBuilder().Build()
}
if cc.dopts.resolverBuilder == nil {
// Only try to parse target when resolver builder is not already set.
Expand Down Expand Up @@ -1007,7 +1003,7 @@ func (ac *addrConn) resetTransport() {
addrs := ac.addrs
backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx)
// This will be the duration that dial gets to finish.
dialDuration := minConnectTimeout
dialDuration := ac.dopts.mct
if ac.dopts.minConnectTimeout != nil {
dialDuration = ac.dopts.minConnectTimeout()
}
Expand Down
34 changes: 20 additions & 14 deletions clientconn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,22 +655,31 @@ func (s) TestCredentialsMisuse(t *testing.T) {
}

func (s) TestWithBackoffConfigDefault(t *testing.T) {
testBackoffConfigSet(t, &DefaultBackoffConfig)
testBackoffStrategySet(t, backoff.NewExponentialBuilder().Build())
}

func (s) TestWithBackoffConfig(t *testing.T) {
b := BackoffConfig{MaxDelay: DefaultBackoffConfig.MaxDelay / 2}
expected := b
testBackoffConfigSet(t, &expected, WithBackoffConfig(b))
md := DefaultBackoffConfig.MaxDelay / 2
expected := backoff.NewExponentialBuilder().MaxDelay(md).Build()
testBackoffStrategySet(t, expected, WithBackoffConfig(BackoffConfig{MaxDelay: md}))
}

func (s) TestWithBackoffMaxDelay(t *testing.T) {
md := DefaultBackoffConfig.MaxDelay / 2
expected := BackoffConfig{MaxDelay: md}
testBackoffConfigSet(t, &expected, WithBackoffMaxDelay(md))
expected := backoff.NewExponentialBuilder().MaxDelay(md).Build()
testBackoffStrategySet(t, expected, WithBackoffMaxDelay(md))
}

func (s) TestWithConnectParams(t *testing.T) {
bd := 2 * time.Second
mltpr := 2.0
jitter := 0.0
crt := ConnectParams{BackoffBaseDelay: bd, BackoffMultiplier: mltpr, BackoffJitter: jitter}
expected := backoff.NewExponentialBuilder().BaseDelay(bd).Multiplier(mltpr).Jitter(jitter).MaxDelay(time.Duration(0)).Build()
testBackoffStrategySet(t, expected, WithConnectParams(crt))
}

func testBackoffConfigSet(t *testing.T, expected *BackoffConfig, opts ...DialOption) {
func testBackoffStrategySet(t *testing.T, expected *backoff.Strategy, opts ...DialOption) {
opts = append(opts, WithInsecure())
conn, err := Dial("passthrough:///foo:80", opts...)
if err != nil {
Expand All @@ -679,19 +688,16 @@ func testBackoffConfigSet(t *testing.T, expected *BackoffConfig, opts ...DialOpt
defer conn.Close()

if conn.dopts.bs == nil {
t.Fatalf("backoff config not set")
t.Fatalf("backoff strategy not set")
}

actual, ok := conn.dopts.bs.(backoff.Exponential)
if !ok {
t.Fatalf("unexpected type of backoff config: %#v", conn.dopts.bs)
t.Fatalf("unexpected type of backoff strategy: %#v", conn.dopts.bs)
}

expectedValue := backoff.Exponential{
MaxDelay: expected.MaxDelay,
}
if actual != expectedValue {
t.Fatalf("unexpected backoff config on connection: %v, want %v", actual, expected)
if actual != expected.(backoff.Exponential) {
t.Errorf("unexpected backoff strategy on connection: %v, want %v", actual, expected)
}
}

Expand Down
32 changes: 27 additions & 5 deletions dialoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ import (
"google.golang.org/grpc/stats"
)

const (
// Minimum time to give a connection to complete.
minConnectTimeout = 20 * time.Second
)

// dialOptions configure a Dial call. dialOptions are set by the DialOption
// values passed to Dial.
type dialOptions struct {
Expand Down Expand Up @@ -68,6 +73,7 @@ type dialOptions struct {
minConnectTimeout func() time.Duration
defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON.
defaultServiceConfigRawJSON *string
mct time.Duration
}

// DialOption configures how we set up the connection.
Expand Down Expand Up @@ -246,21 +252,36 @@ func WithServiceConfig(c <-chan ServiceConfig) DialOption {
})
}

// WithConnectParams configures the dialer to use the provided backoff
// parameters for the algorithm defined in
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
// This will override all the default values with the ones provided here. So,
// use with caution.
//
// This API is EXPERIMENTAL.
func WithConnectParams(p ConnectParams) DialOption {
b := backoff.NewExponentialBuilder()
b.BaseDelay(p.BackoffBaseDelay).Multiplier(p.BackoffMultiplier).Jitter(p.BackoffJitter).MaxDelay(p.BackoffMaxDelay)
return newFuncDialOption(func(o *dialOptions) {
o.bs = b.Build()
o.mct = p.MinConnectTimeout
})
}

// WithBackoffMaxDelay configures the dialer to use the provided maximum delay
// when backing off after failed connection attempts.
//
// Deprecated: use WithConnectParams instead.
func WithBackoffMaxDelay(md time.Duration) DialOption {
return WithBackoffConfig(BackoffConfig{MaxDelay: md})
}

// WithBackoffConfig configures the dialer to use the provided backoff
// parameters after connection failures.
//
// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up
// for use.
// Deprecated: use WithConnectParams instead.
func WithBackoffConfig(b BackoffConfig) DialOption {
return withBackoff(backoff.Exponential{
MaxDelay: b.MaxDelay,
})
return withBackoff(backoff.NewExponentialBuilder().MaxDelay(b.MaxDelay).Build())
}

// withBackoff sets the backoff strategy used for connectRetryNum after a failed
Expand Down Expand Up @@ -539,6 +560,7 @@ func defaultDialOptions() dialOptions {
WriteBufferSize: defaultWriteBufSize,
ReadBufferSize: defaultReadBufSize,
},
mct: minConnectTimeout,
}
}

Expand Down
4 changes: 1 addition & 3 deletions health/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ import (
"google.golang.org/grpc/status"
)

const maxDelay = 120 * time.Second

var backoffStrategy = backoff.Exponential{MaxDelay: maxDelay}
var backoffStrategy = backoff.NewExponentialBuilder().Build()
var backoffFunc = func(ctx context.Context, retries int) bool {
d := backoffStrategy.Backoff(retries)
timer := time.NewTimer(d)
Expand Down

0 comments on commit 452f9d8

Please sign in to comment.