Skip to content

feat: add ClientName option #2333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ type ClusterOptions struct {
// A seed list of host:port addresses of cluster nodes.
Addrs []string

// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
ClientName string

// NewClient creates a cluster node client with provided name and options.
NewClient func(opt *Options) *Client

Expand Down Expand Up @@ -208,6 +211,7 @@ func setupClusterConn(u *url.URL, host string, o *ClusterOptions) (*ClusterOptio
func setupClusterQueryParams(u *url.URL, o *ClusterOptions) (*ClusterOptions, error) {
q := queryOptions{q: u.Query()}

o.ClientName = q.string("client_name")
o.MaxRedirects = q.int("max_redirects")
o.ReadOnly = q.bool("read_only")
o.RouteByLatency = q.bool("route_by_latency")
Expand Down Expand Up @@ -250,8 +254,9 @@ func setupClusterQueryParams(u *url.URL, o *ClusterOptions) (*ClusterOptions, er

func (opt *ClusterOptions) clientOptions() *Options {
return &Options{
Dialer: opt.Dialer,
OnConnect: opt.OnConnect,
ClientName: opt.ClientName,
Dialer: opt.Dialer,
OnConnect: opt.OnConnect,

Username: opt.Username,
Password: opt.Password,
Expand Down Expand Up @@ -871,7 +876,7 @@ func (c *ClusterClient) Close() error {
return c.nodes.Close()
}

// Do creates a Cmd from the args and processes the cmd.
// Do create a Cmd from the args and processes the cmd.
func (c *ClusterClient) Do(ctx context.Context, args ...interface{}) *Cmd {
cmd := NewCmd(ctx, args...)
_ = c.Process(ctx, cmd)
Expand Down
19 changes: 19 additions & 0 deletions cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ var _ = Describe("ClusterClient", func() {
Describe("ClusterClient", func() {
BeforeEach(func() {
opt = redisClusterOptions()
opt.ClientName = "cluster_hi"
client = cluster.newClusterClient(ctx, opt)

err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error {
Expand Down Expand Up @@ -679,6 +680,20 @@ var _ = Describe("ClusterClient", func() {
Expect(assertSlotsEqual(res, wanted)).NotTo(HaveOccurred())
})

It("should cluster client setname", func() {
err := client.ForEachShard(ctx, func(ctx context.Context, c *redis.Client) error {
return c.Ping(ctx).Err()
})
Expect(err).NotTo(HaveOccurred())

_ = client.ForEachShard(ctx, func(ctx context.Context, c *redis.Client) error {
val, err := c.ClientList(ctx).Result()
Expect(err).NotTo(HaveOccurred())
Expect(val).Should(ContainSubstring("name=cluster_hi"))
return nil
})
})

It("should CLUSTER NODES", func() {
res, err := client.ClusterNodes(ctx).Result()
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -1408,6 +1423,10 @@ func TestParseClusterURL(t *testing.T) {
test: "UseDefault",
url: "redis://localhost:123?conn_max_idle_time=",
o: &redis.ClusterOptions{Addrs: []string{"localhost:123"}, ConnMaxIdleTime: 0},
}, {
test: "ClientName",
url: "redis://localhost:123?client_name=cluster_hi",
o: &redis.ClusterOptions{Addrs: []string{"localhost:123"}, ClientName: "cluster_hi"},
}, {
test: "UseDefaultMissing=",
url: "redis://localhost:123?conn_max_idle_time",
Expand Down
6 changes: 5 additions & 1 deletion options.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ type Limiter interface {
ReportResult(result error)
}

// Options keeps the settings to setup redis connection.
// Options keeps the settings to set up redis connection.
type Options struct {
// The network type, either tcp or unix.
// Default is tcp.
Network string
// host:port address.
Addr string

// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
ClientName string

// Dialer creates new network connection and has priority over
// Network and Addr options.
Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
Expand Down Expand Up @@ -426,6 +429,7 @@ func setupConnParams(u *url.URL, o *Options) (*Options, error) {
o.DB = db
}

o.ClientName = q.string("client_name")
o.MaxRetries = q.int("max_retries")
o.MinRetryBackoff = q.duration("min_retry_backoff")
o.MaxRetryBackoff = q.duration("max_retry_backoff")
Expand Down
3 changes: 3 additions & 0 deletions options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ func TestParseURL(t *testing.T) {
}, {
url: "redis://localhost:123/?db=2&conn_max_idle_time", // missing "=" at the end
o: &Options{Addr: "localhost:123", DB: 2, ConnMaxIdleTime: 0},
}, {
url: "redis://localhost:123/?db=2&client_name=hi", // client name
o: &Options{Addr: "localhost:123", DB: 2, ClientName: "hi"},
}, {
url: "unix:///tmp/redis.sock",
o: &Options{Addr: "/tmp/redis.sock"},
Expand Down
4 changes: 4 additions & 0 deletions redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
pipe.ReadOnly(ctx)
}

if c.opt.ClientName != "" {
pipe.ClientSetName(ctx, c.opt.ClientName)
}

return nil
})
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions redis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,21 @@ var _ = Describe("Client", func() {
Expect(db2.Close()).NotTo(HaveOccurred())
})

It("should client setname", func() {
opt := redisOptions()
opt.ClientName = "hi"
db := redis.NewClient(opt)

defer func() {
Expect(db.Close()).NotTo(HaveOccurred())
}()

Expect(db.Ping(ctx).Err()).NotTo(HaveOccurred())
val, err := db.ClientList(ctx).Result()
Expect(err).NotTo(HaveOccurred())
Expect(val).Should(ContainSubstring("name=hi"))
})

It("processes custom commands", func() {
cmd := redis.NewCmd(ctx, "PING")
_ = client.Process(ctx, cmd)
Expand Down
10 changes: 7 additions & 3 deletions ring.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type RingOptions struct {
// NewClient creates a shard client with provided options.
NewClient func(opt *Options) *Client

// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
ClientName string

// Frequency of PING commands sent to check shards availability.
// Shard is considered down after 3 subsequent failed checks.
HeartbeatFrequency time.Duration
Expand Down Expand Up @@ -129,8 +132,9 @@ func (opt *RingOptions) init() {

func (opt *RingOptions) clientOptions() *Options {
return &Options{
Dialer: opt.Dialer,
OnConnect: opt.OnConnect,
ClientName: opt.ClientName,
Dialer: opt.Dialer,
OnConnect: opt.OnConnect,

Username: opt.Username,
Password: opt.Password,
Expand Down Expand Up @@ -522,7 +526,7 @@ func (c *Ring) SetAddrs(addrs map[string]string) {
c.sharding.SetAddrs(addrs)
}

// Do creates a Cmd from the args and processes the cmd.
// Do create a Cmd from the args and processes the cmd.
func (c *Ring) Do(ctx context.Context, args ...interface{}) *Cmd {
cmd := NewCmd(ctx, args...)
_ = c.Process(ctx, cmd)
Expand Down
15 changes: 15 additions & 0 deletions ring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var _ = Describe("Redis Ring", func() {

BeforeEach(func() {
opt := redisRingOptions()
opt.ClientName = "ring_hi"
opt.HeartbeatFrequency = heartbeat
ring = redis.NewRing(opt)

Expand All @@ -50,6 +51,20 @@ var _ = Describe("Redis Ring", func() {
Expect(err).To(MatchError("context canceled"))
})

It("should ring client setname", func() {
err := ring.ForEachShard(ctx, func(ctx context.Context, c *redis.Client) error {
return c.Ping(ctx).Err()
})
Expect(err).NotTo(HaveOccurred())

_ = ring.ForEachShard(ctx, func(ctx context.Context, c *redis.Client) error {
val, err := c.ClientList(ctx).Result()
Expect(err).NotTo(HaveOccurred())
Expect(val).Should(ContainSubstring("name=ring_hi"))
return nil
})
})

It("distributes keys", func() {
setRingKeys()

Expand Down
11 changes: 9 additions & 2 deletions sentinel.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type FailoverOptions struct {
// A seed list of host:port addresses of sentinel nodes.
SentinelAddrs []string

// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
ClientName string

// If specified with SentinelPassword, enables ACL-based authentication (via
// AUTH <user> <pass>).
SentinelUsername string
Expand Down Expand Up @@ -78,7 +81,8 @@ type FailoverOptions struct {

func (opt *FailoverOptions) clientOptions() *Options {
return &Options{
Addr: "FailoverClient",
Addr: "FailoverClient",
ClientName: opt.ClientName,

Dialer: opt.Dialer,
OnConnect: opt.OnConnect,
Expand Down Expand Up @@ -110,7 +114,8 @@ func (opt *FailoverOptions) clientOptions() *Options {

func (opt *FailoverOptions) sentinelOptions(addr string) *Options {
return &Options{
Addr: addr,
Addr: addr,
ClientName: opt.ClientName,

Dialer: opt.Dialer,
OnConnect: opt.OnConnect,
Expand Down Expand Up @@ -141,6 +146,8 @@ func (opt *FailoverOptions) sentinelOptions(addr string) *Options {

func (opt *FailoverOptions) clusterOptions() *ClusterOptions {
return &ClusterOptions{
ClientName: opt.ClientName,

Dialer: opt.Dialer,
OnConnect: opt.OnConnect,

Expand Down
24 changes: 24 additions & 0 deletions sentinel_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package redis_test

import (
"context"
"net"

. "github.com/onsi/ginkgo"
Expand All @@ -17,6 +18,7 @@ var _ = Describe("Sentinel", func() {

BeforeEach(func() {
client = redis.NewFailoverClient(&redis.FailoverOptions{
ClientName: "sentinel_hi",
MasterName: sentinelName,
SentinelAddrs: sentinelAddrs,
MaxRetries: -1,
Expand Down Expand Up @@ -125,6 +127,13 @@ var _ = Describe("Sentinel", func() {
err := client.Ping(ctx).Err()
Expect(err).NotTo(HaveOccurred())
})

It("should sentinel client setname", func() {
Expect(client.Ping(ctx).Err()).NotTo(HaveOccurred())
val, err := client.ClientList(ctx).Result()
Expect(err).NotTo(HaveOccurred())
Expect(val).Should(ContainSubstring("name=sentinel_hi"))
})
})

var _ = Describe("NewFailoverClusterClient", func() {
Expand All @@ -134,6 +143,7 @@ var _ = Describe("NewFailoverClusterClient", func() {

BeforeEach(func() {
client = redis.NewFailoverClusterClient(&redis.FailoverOptions{
ClientName: "sentinel_cluster_hi",
MasterName: sentinelName,
SentinelAddrs: sentinelAddrs,

Expand Down Expand Up @@ -213,6 +223,20 @@ var _ = Describe("NewFailoverClusterClient", func() {
_, err = startRedis(masterPort)
Expect(err).NotTo(HaveOccurred())
})

It("should sentinel cluster client setname", func() {
err := client.ForEachShard(ctx, func(ctx context.Context, c *redis.Client) error {
return c.Ping(ctx).Err()
})
Expect(err).NotTo(HaveOccurred())

_ = client.ForEachShard(ctx, func(ctx context.Context, c *redis.Client) error {
val, err := c.ClientList(ctx).Result()
Expect(err).NotTo(HaveOccurred())
Expect(val).Should(ContainSubstring("name=sentinel_cluster_hi"))
return nil
})
})
})

var _ = Describe("SentinelAclAuth", func() {
Expand Down
18 changes: 12 additions & 6 deletions universal.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ type UniversalOptions struct {
// of cluster/sentinel nodes.
Addrs []string

// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
ClientName string

// Database to be selected after connecting to the server.
// Only single-node and failover clients.
DB int
Expand Down Expand Up @@ -69,9 +72,10 @@ func (o *UniversalOptions) Cluster() *ClusterOptions {
}

return &ClusterOptions{
Addrs: o.Addrs,
Dialer: o.Dialer,
OnConnect: o.OnConnect,
Addrs: o.Addrs,
ClientName: o.ClientName,
Dialer: o.Dialer,
OnConnect: o.OnConnect,

Username: o.Username,
Password: o.Password,
Expand Down Expand Up @@ -112,6 +116,7 @@ func (o *UniversalOptions) Failover() *FailoverOptions {
return &FailoverOptions{
SentinelAddrs: o.Addrs,
MasterName: o.MasterName,
ClientName: o.ClientName,

Dialer: o.Dialer,
OnConnect: o.OnConnect,
Expand Down Expand Up @@ -151,9 +156,10 @@ func (o *UniversalOptions) Simple() *Options {
}

return &Options{
Addr: addr,
Dialer: o.Dialer,
OnConnect: o.OnConnect,
Addr: addr,
ClientName: o.ClientName,
Dialer: o.Dialer,
OnConnect: o.OnConnect,

DB: o.DB,
Username: o.Username,
Expand Down