Skip to content

Commit d344ec3

Browse files
committed
fix: Recycle connections in some Redis Cluster scenarios
This issue was surfaced in a Cloud Provider solution that used for rolling out new nodes using the same address (hostname) of the nodes that will be replaced in a Redis Cluster, while the former ones once depromoted as Slaves would continue in service during some mintues for redirecting traffic. The solution basically identifies when the connection could be stale since a MOVED response will be returned using the same address (hostname) that is being used by the connection. At that moment we consider the connection as no longer usable forcing to recycle the connection.
1 parent 5072031 commit d344ec3

File tree

3 files changed

+22
-6
lines changed

3 files changed

+22
-6
lines changed

error.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func isRedisError(err error) bool {
6565
return ok
6666
}
6767

68-
func isBadConn(err error, allowTimeout bool) bool {
68+
func isBadConn(err error, allowTimeout bool, addr string) bool {
6969
switch err {
7070
case nil:
7171
return false
@@ -74,9 +74,16 @@ func isBadConn(err error, allowTimeout bool) bool {
7474
}
7575

7676
if isRedisError(err) {
77-
// Close connections in read only state in case domain addr is used
78-
// and domain resolves to a different Redis Server. See #790.
79-
return isReadOnlyError(err)
77+
if isReadOnlyError(err) {
78+
// Close connections in read only state in case domain addr is used
79+
// and domain resolves to a different Redis Server. See #790.
80+
return true
81+
} else if isMovedSameConnAddr(err, addr) {
82+
// Close connections when we are asked to move to the same addr
83+
// of the connection. Force a DNS resolution when all connections
84+
// of the pool are recycled
85+
return true
86+
}
8087
}
8188

8289
if allowTimeout {
@@ -119,6 +126,15 @@ func isReadOnlyError(err error) bool {
119126
return strings.HasPrefix(err.Error(), "READONLY ")
120127
}
121128

129+
func isMovedSameConnAddr(err error, addr string) bool {
130+
redisError := err.Error()
131+
if !strings.HasPrefix(redisError, "MOVED ") {
132+
return false
133+
}
134+
return strings.HasSuffix(redisError, addr)
135+
}
136+
137+
122138
//------------------------------------------------------------------------------
123139

124140
type timeoutError interface {

pubsub.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func (c *PubSub) releaseConn(ctx context.Context, cn *pool.Conn, err error, allo
141141
if c.cn != cn {
142142
return
143143
}
144-
if isBadConn(err, allowTimeout) {
144+
if isBadConn(err, allowTimeout, c.opt.Addr) {
145145
c.reconnect(ctx, err)
146146
}
147147
}

redis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ func (c *baseClient) releaseConn(ctx context.Context, cn *pool.Conn, err error)
261261
c.opt.Limiter.ReportResult(err)
262262
}
263263

264-
if isBadConn(err, false) {
264+
if isBadConn(err, false, c.opt.Addr) {
265265
c.connPool.Remove(ctx, cn, err)
266266
} else {
267267
c.connPool.Put(ctx, cn)

0 commit comments

Comments
 (0)