From 07898eade0b221f1475cbcc0775e7619f965fce3 Mon Sep 17 00:00:00 2001 From: Jiale Lin <63439129+ljluestc@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:20:52 -0700 Subject: [PATCH] fix: parse DB number from redis-sentinel URI path (#669) Previously, parseRedisSentinelURI ignored the /dbnumber path segment, making it impossible to connect to any DB other than 0 via sentinel URIs. This adds DB extraction from the URI path, consistent with how parseRedisURI already handles it for redis:// and rediss:// schemes. Closes #669 --- asynq.go | 13 +++++++++++-- asynq_test.go | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/asynq.go b/asynq.go index c27d0f7..45989d3 100644 --- a/asynq.go +++ b/asynq.go @@ -471,7 +471,7 @@ func (opt RedisClusterClientOpt) MakeRedisClient() interface{} { // redis://[:password@]host[:port][/dbnumber] // rediss://[:password@]host[:port][/dbnumber] // redis-socket://[:password@]path[?db=dbnumber] -// redis-sentinel://[:password@]host1[:port][,host2:[:port]][,hostN:[:port]][?master=masterName] +// redis-sentinel://[:password@]host1[:port][,host2:[:port]][,hostN:[:port]][/dbnumber][?master=masterName] func ParseRedisURI(uri string) (RedisConnOpt, error) { u, err := url.Parse(uri) if err != nil { @@ -545,11 +545,20 @@ func parseRedisSocketURI(u *url.URL) (RedisConnOpt, error) { func parseRedisSentinelURI(u *url.URL) (RedisConnOpt, error) { addrs := strings.Split(u.Host, ",") master := u.Query().Get("master") + var db int + var err error + if len(u.Path) > 0 { + xs := strings.Split(strings.Trim(u.Path, "/"), "/") + db, err = strconv.Atoi(xs[0]) + if err != nil { + return nil, fmt.Errorf("asynq: could not parse redis sentinel uri: database number should be the first segment of the path") + } + } var password string if v, ok := u.User.Password(); ok { password = v } - return RedisFailoverClientOpt{MasterName: master, SentinelAddrs: addrs, SentinelPassword: password}, nil + return RedisFailoverClientOpt{MasterName: master, SentinelAddrs: addrs, SentinelPassword: password, DB: db}, nil } // ResultWriter is a client interface to write result data for a task. diff --git a/asynq_test.go b/asynq_test.go index 08afa82..88c8748 100644 --- a/asynq_test.go +++ b/asynq_test.go @@ -148,6 +148,23 @@ func TestParseRedisURI(t *testing.T) { SentinelPassword: "mypassword", }, }, + { + "redis-sentinel://localhost:5000,localhost:5001,localhost:5002/3?master=mymaster", + RedisFailoverClientOpt{ + MasterName: "mymaster", + SentinelAddrs: []string{"localhost:5000", "localhost:5001", "localhost:5002"}, + DB: 3, + }, + }, + { + "redis-sentinel://:mypassword@localhost:5000,localhost:5001,localhost:5002/7?master=mymaster", + RedisFailoverClientOpt{ + MasterName: "mymaster", + SentinelAddrs: []string{"localhost:5000", "localhost:5001", "localhost:5002"}, + SentinelPassword: "mypassword", + DB: 7, + }, + }, } for _, tc := range tests { @@ -188,6 +205,10 @@ func TestParseRedisURIErrors(t *testing.T) { "non integer for db numbers for socket", "redis-socket:///some/path/to/redis?db=one", }, + { + "non integer for db number for sentinel", + "redis-sentinel://localhost:5000/abc?master=mymaster", + }, } for _, tc := range tests {