From d678a018f4a5cfa5102b94011dceaf244421f3fa Mon Sep 17 00:00:00 2001 From: Alexander Menshchikov Date: Fri, 10 Nov 2023 10:45:04 +0300 Subject: [PATCH 1/2] Add FailoverClusterClient support + fix example/hset-struct go.sum --- example/hset-struct/go.sum | 2 -- universal.go | 13 ++++++++++--- universal_test.go | 12 +++++++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/example/hset-struct/go.sum b/example/hset-struct/go.sum index 1602e702e5..5496d29e58 100644 --- a/example/hset-struct/go.sum +++ b/example/hset-struct/go.sum @@ -1,7 +1,5 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/universal.go b/universal.go index 0a25bf221b..f66e6c25df 100644 --- a/universal.go +++ b/universal.go @@ -154,6 +154,9 @@ func (o *UniversalOptions) Failover() *FailoverOptions { SentinelUsername: o.SentinelUsername, SentinelPassword: o.SentinelPassword, + RouteByLatency: o.RouteByLatency, + RouteRandomly: o.RouteRandomly, + MaxRetries: o.MaxRetries, MinRetryBackoff: o.MinRetryBackoff, MaxRetryBackoff: o.MaxRetryBackoff, @@ -260,10 +263,14 @@ var ( // 2. if the number of Addrs is two or more, a ClusterClient is returned. // 3. Otherwise, a single-node Client is returned. func NewUniversalClient(opts *UniversalOptions) UniversalClient { - if opts.MasterName != "" { + switch { + case opts.MasterName != "" && (opts.RouteByLatency || opts.RouteRandomly): + return NewFailoverClusterClient(opts.Failover()) + case opts.MasterName != "": return NewFailoverClient(opts.Failover()) - } else if len(opts.Addrs) > 1 || opts.IsClusterMode { + case len(opts.Addrs) > 1 || opts.IsClusterMode: return NewClusterClient(opts.Cluster()) + default: + return NewClient(opts.Simple()) } - return NewClient(opts.Simple()) } diff --git a/universal_test.go b/universal_test.go index e389fe4fb2..f965253fc1 100644 --- a/universal_test.go +++ b/universal_test.go @@ -24,6 +24,16 @@ var _ = Describe("UniversalClient", func() { Expect(client.Ping(ctx).Err()).NotTo(HaveOccurred()) }) + It("should connect to failover cluster", Label("NonRedisEnterprise"), func() { + client = redis.NewUniversalClient(&redis.UniversalOptions{ + MasterName: sentinelName, + RouteRandomly: true, + Addrs: sentinelAddrs, + }) + _, ok := client.(*redis.ClusterClient) + Expect(ok).To(BeTrue(), "expected a ClusterClient") + }) + It("should connect to simple servers", func() { client = redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{redisAddr}, @@ -79,6 +89,7 @@ var _ = Describe("UniversalClient", func() { err = client.Set(ctx, "somekey", "somevalue", 0).Err() Expect(err).To(HaveOccurred()) }) + It("should connect to clusters if IsClusterMode is set even if only a single address is provided", Label("NonRedisEnterprise"), func() { client = redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{cluster.addrs()[0]}, @@ -96,4 +107,3 @@ var _ = Describe("UniversalClient", func() { Expect(client.ClusterSlots(ctx).Val()).To(HaveLen(3)) }) }) - From 6c8231f59fb236dace2760d547146ccaf41cb873 Mon Sep 17 00:00:00 2001 From: Alexander Menshchikov Date: Thu, 20 Mar 2025 09:05:22 +0300 Subject: [PATCH 2/2] Improve NewUniversalClient comment --- universal.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/universal.go b/universal.go index f66e6c25df..3d91dd493e 100644 --- a/universal.go +++ b/universal.go @@ -259,12 +259,16 @@ var ( // NewUniversalClient returns a new multi client. The type of the returned client depends // on the following conditions: // -// 1. If the MasterName option is specified, a sentinel-backed FailoverClient is returned. -// 2. if the number of Addrs is two or more, a ClusterClient is returned. -// 3. Otherwise, a single-node Client is returned. +// 1. If the MasterName option is specified with RouteByLatency, RouteRandomly or IsClusterMode, +// a FailoverClusterClient is returned. +// 2. If the MasterName option is specified without RouteByLatency, RouteRandomly or IsClusterMode, +// a sentinel-backed FailoverClient is returned. +// 3. If the number of Addrs is two or more, or IsClusterMode option is specified, +// a ClusterClient is returned. +// 4. Otherwise, a single-node Client is returned. func NewUniversalClient(opts *UniversalOptions) UniversalClient { switch { - case opts.MasterName != "" && (opts.RouteByLatency || opts.RouteRandomly): + case opts.MasterName != "" && (opts.RouteByLatency || opts.RouteRandomly || opts.IsClusterMode): return NewFailoverClusterClient(opts.Failover()) case opts.MasterName != "": return NewFailoverClient(opts.Failover())