From 0857def30e115dc43fe9eb6a13bb5c180612ad6d Mon Sep 17 00:00:00 2001 From: Allen Ray Date: Wed, 17 Jan 2024 11:45:36 -0500 Subject: [PATCH] add backoff to client config Signed-off-by: Allen Ray --- client/v3/client.go | 19 ++++++++++++++++-- client/v3/client_test.go | 42 ++++++++++++++++++++++++++++++++++++++++ client/v3/config.go | 9 +++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/client/v3/client.go b/client/v3/client.go index 16fbb5de211..c28f53c9d40 100644 --- a/client/v3/client.go +++ b/client/v3/client.go @@ -239,15 +239,30 @@ func (c *Client) dialSetupOpts(creds grpccredentials.TransportCredentials, dopts opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) } + unaryMaxRetries := defaultUnaryMaxRetries + if c.cfg.MaxUnaryRetries > 0 { + unaryMaxRetries = c.cfg.MaxUnaryRetries + } + + backoffWaitBetween := defaultBackoffWaitBetween + if c.cfg.BackoffWaitBetween > 0 { + backoffWaitBetween = c.cfg.BackoffWaitBetween + } + + backoffJitterFraction := defaultBackoffJitterFraction + if c.cfg.BackoffJitterFraction > 0 { + backoffJitterFraction = c.cfg.BackoffJitterFraction + } + // Interceptor retry and backoff. // TODO: Replace all of clientv3/retry.go with RetryPolicy: // https://github.com/grpc/grpc-proto/blob/cdd9ed5c3d3f87aef62f373b93361cf7bddc620d/grpc/service_config/service_config.proto#L130 - rrBackoff := withBackoff(c.roundRobinQuorumBackoff(defaultBackoffWaitBetween, defaultBackoffJitterFraction)) + rrBackoff := withBackoff(c.roundRobinQuorumBackoff(backoffWaitBetween, backoffJitterFraction)) opts = append(opts, // Disable stream retry by default since go-grpc-middleware/retry does not support client streams. // Streams that are safe to retry are enabled individually. grpc.WithStreamInterceptor(c.streamClientInterceptor(withMax(0), rrBackoff)), - grpc.WithUnaryInterceptor(c.unaryClientInterceptor(withMax(defaultUnaryMaxRetries), rrBackoff)), + grpc.WithUnaryInterceptor(c.unaryClientInterceptor(withMax(unaryMaxRetries), rrBackoff)), ) return opts diff --git a/client/v3/client_test.go b/client/v3/client_test.go index 350b1960a10..db8bb1773f9 100644 --- a/client/v3/client_test.go +++ b/client/v3/client_test.go @@ -156,6 +156,48 @@ func TestDialNoTimeout(t *testing.T) { c.Close() } +func TestMaxUnaryRetries(t *testing.T) { + maxUnaryRetries := uint(10) + cfg := Config{ + Endpoints: []string{"127.0.0.1:12345"}, + MaxUnaryRetries: maxUnaryRetries, + } + c, err := NewClient(t, cfg) + require.NoError(t, err) + require.NotNil(t, c) + defer c.Close() + + require.Equal(t, maxUnaryRetries, c.cfg.MaxUnaryRetries) +} + +func TestBackoff(t *testing.T) { + backoffWaitBetween := 100 * time.Millisecond + cfg := Config{ + Endpoints: []string{"127.0.0.1:12345"}, + BackoffWaitBetween: backoffWaitBetween, + } + c, err := NewClient(t, cfg) + require.NoError(t, err) + require.NotNil(t, c) + defer c.Close() + + require.Equal(t, backoffWaitBetween, c.cfg.BackoffWaitBetween) +} + +func TestBackoffJitterFraction(t *testing.T) { + backoffJitterFraction := float64(0.9) + cfg := Config{ + Endpoints: []string{"127.0.0.1:12345"}, + BackoffJitterFraction: backoffJitterFraction, + } + c, err := NewClient(t, cfg) + require.NoError(t, err) + require.NotNil(t, c) + defer c.Close() + + require.Equal(t, backoffJitterFraction, c.cfg.BackoffJitterFraction) +} + func TestIsHaltErr(t *testing.T) { assert.Equal(t, isHaltErr(context.TODO(), errors.New("etcdserver: some etcdserver error")), diff --git a/client/v3/config.go b/client/v3/config.go index 4a26714a864..89b40ce12ec 100644 --- a/client/v3/config.go +++ b/client/v3/config.go @@ -90,6 +90,15 @@ type Config struct { // PermitWithoutStream when set will allow client to send keepalive pings to server without any active streams(RPCs). PermitWithoutStream bool `json:"permit-without-stream"` + // MaxUnaryRetries is the maximum number of retries for unary RPCs. + MaxUnaryRetries uint `json:"max-unary-retries"` + + // BackoffWaitBetween is the wait time before retrying an RPC. + BackoffWaitBetween time.Duration `json:"backoff-wait-between"` + + // BackoffJitterFraction is the jitter fraction to randomize backoff wait time. + BackoffJitterFraction float64 `json:"backoff-jitter-fraction"` + // TODO: support custom balancer picker }