Rename ReadOnly to SlaveOnly and cleanup

This commit is contained in:
Vladimir Mihailenco 2020-09-09 16:20:58 +03:00
parent 6c85ee767a
commit 4877841b11
2 changed files with 49 additions and 37 deletions

View File

@ -26,8 +26,8 @@ type FailoverOptions struct {
// Sentinel password from "requirepass <password>" (if enabled) in Sentinel configuration // Sentinel password from "requirepass <password>" (if enabled) in Sentinel configuration
SentinelPassword string SentinelPassword string
// Enables read-only commands on slave nodes. // Route all commands to slave read-only nodes.
ReadOnly bool SlaveOnly bool
// Following options are copied from Options struct. // Following options are copied from Options struct.
@ -57,7 +57,7 @@ type FailoverOptions struct {
} }
func (opt *FailoverOptions) options() *Options { func (opt *FailoverOptions) options() *Options {
return &Options{ redisOpt := &Options{
Addr: "FailoverClient", Addr: "FailoverClient",
Dialer: opt.Dialer, Dialer: opt.Dialer,
@ -83,13 +83,13 @@ func (opt *FailoverOptions) options() *Options {
MaxConnAge: opt.MaxConnAge, MaxConnAge: opt.MaxConnAge,
TLSConfig: opt.TLSConfig, TLSConfig: opt.TLSConfig,
sentinelReadOnly: opt.ReadOnly,
} }
redisOpt.init()
return redisOpt
} }
func (opt *FailoverOptions) clusterOptions() *ClusterOptions { func (opt *FailoverOptions) clusterOptions() *ClusterOptions {
return &ClusterOptions{ clusterOpt := &ClusterOptions{
Dialer: opt.Dialer, Dialer: opt.Dialer,
OnConnect: opt.OnConnect, OnConnect: opt.OnConnect,
@ -113,25 +113,24 @@ func (opt *FailoverOptions) clusterOptions() *ClusterOptions {
TLSConfig: opt.TLSConfig, TLSConfig: opt.TLSConfig,
} }
clusterOpt.init()
return clusterOpt
} }
// NewFailoverClient returns a Redis client that uses Redis Sentinel // NewFailoverClient returns a Redis client that uses Redis Sentinel
// for automatic failover. It's safe for concurrent use by multiple // for automatic failover. It's safe for concurrent use by multiple
// goroutines. // goroutines.
func NewFailoverClient(failoverOpt *FailoverOptions) *Client { func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
opt := failoverOpt.options()
opt.init()
failover := &sentinelFailover{ failover := &sentinelFailover{
masterName: failoverOpt.MasterName, masterName: failoverOpt.MasterName,
sentinelAddrs: failoverOpt.SentinelAddrs, sentinelAddrs: failoverOpt.SentinelAddrs,
sentinelPassword: failoverOpt.SentinelPassword, sentinelPassword: failoverOpt.SentinelPassword,
opt: opt, opt: failoverOpt.options(),
} }
// TODO: this overwrites original dialer opt := failoverOpt.options()
opt.Dialer = failover.dial opt.Dialer = masterSlaveDialer(failover, failoverOpt.SlaveOnly)
connPool := newConnPool(opt) connPool := newConnPool(opt)
failover.onFailover = func(ctx context.Context, addr string) { failover.onFailover = func(ctx context.Context, addr string) {
@ -150,8 +149,35 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
return &c return &c
} }
func masterSlaveDialer(
failover *sentinelFailover, slaveOnly bool,
) func(ctx context.Context, network, addr string) (net.Conn, error) {
return func(ctx context.Context, network, _ string) (net.Conn, error) {
var addr string
var err error
if slaveOnly {
addr, err = failover.RandomSlaveAddr(ctx)
} else {
addr, err = failover.MasterAddr(ctx)
if err == nil {
failover.trySwitchMaster(ctx, addr)
}
}
if err != nil {
return nil, err
}
if failover.opt.Dialer != nil {
return failover.opt.Dialer(ctx, network, addr)
}
return net.DialTimeout("tcp", addr, failover.opt.DialTimeout)
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// SentinelClient is a client for a Redis Sentinel.
type SentinelClient struct { type SentinelClient struct {
*baseClient *baseClient
ctx context.Context ctx context.Context
@ -358,34 +384,12 @@ func (c *sentinelFailover) closeSentinel() error {
return firstErr return firstErr
} }
func (c *sentinelFailover) dial(ctx context.Context, network, _ string) (net.Conn, error) {
var addr string
var err error
if c.opt.sentinelReadOnly {
addr, err = c.RandomSlaveAddr(ctx)
} else {
addr, err = c.MasterAddr(ctx)
if err == nil {
c.trySwitchMaster(ctx, addr)
}
}
if err != nil {
return nil, err
}
if c.opt.Dialer != nil {
return c.opt.Dialer(ctx, network, addr)
}
return net.DialTimeout("tcp", addr, c.opt.DialTimeout)
}
func (c *sentinelFailover) RandomSlaveAddr(ctx context.Context) (string, error) { func (c *sentinelFailover) RandomSlaveAddr(ctx context.Context) (string, error) {
addresses, err := c.slaveAddresses(ctx) addresses, err := c.slaveAddresses(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
if len(addresses) < 1 { if len(addresses) == 0 {
return c.MasterAddr(ctx) return c.MasterAddr(ctx)
} }
return addresses[rand.Intn(len(addresses))], nil return addresses[rand.Intn(len(addresses))], nil

View File

@ -28,7 +28,7 @@ var _ = Describe("Sentinel", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Verify. // Verify.
val, err := sentinelMaster.Get(ctx, "foo").Result() val, err := client.Get(ctx, "foo").Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(val).To(Equal("master")) Expect(val).To(Equal("master"))
@ -78,6 +78,10 @@ var _ = Describe("Sentinel", func() {
}, "15s", "100ms").Should(Receive(&msg)) }, "15s", "100ms").Should(Receive(&msg))
Expect(msg.Channel).To(Equal("foo")) Expect(msg.Channel).To(Equal("foo"))
Expect(msg.Payload).To(Equal("hello")) Expect(msg.Payload).To(Equal("hello"))
Expect(sentinelMaster.Close()).NotTo(HaveOccurred())
sentinelMaster, err = startRedis(sentinelMasterPort)
Expect(err).NotTo(HaveOccurred())
}) })
It("supports DB selection", func() { It("supports DB selection", func() {
@ -114,7 +118,7 @@ var _ = Describe("NewFailoverClusterClient", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Verify. // Verify.
val, err := sentinelMaster.Get(ctx, "foo").Result() val, err := client.Get(ctx, "foo").Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(val).To(Equal("master")) Expect(val).To(Equal("master"))
@ -164,5 +168,9 @@ var _ = Describe("NewFailoverClusterClient", func() {
}, "15s", "100ms").Should(Receive(&msg)) }, "15s", "100ms").Should(Receive(&msg))
Expect(msg.Channel).To(Equal("foo")) Expect(msg.Channel).To(Equal("foo"))
Expect(msg.Payload).To(Equal("hello")) Expect(msg.Payload).To(Equal("hello"))
Expect(sentinelMaster.Close()).NotTo(HaveOccurred())
sentinelMaster, err = startRedis(sentinelMasterPort)
Expect(err).NotTo(HaveOccurred())
}) })
}) })