diff --git a/error.go b/error.go index a7bf159c..ec2224c0 100644 --- a/error.go +++ b/error.go @@ -53,6 +53,9 @@ func shouldRetry(err error, retryTimeout bool) bool { return true case nil, context.Canceled, context.DeadlineExceeded: return false + case pool.ErrPoolTimeout: + // connection pool timeout, increase retries. #3289 + return true } if v, ok := err.(timeoutError); ok { diff --git a/error_test.go b/error_test.go new file mode 100644 index 00000000..da9a471a --- /dev/null +++ b/error_test.go @@ -0,0 +1,65 @@ +package redis_test + +import ( + "context" + "errors" + "io" + + . "github.com/bsm/ginkgo/v2" + . "github.com/bsm/gomega" + "github.com/redis/go-redis/v9" +) + +type testTimeout struct { + timeout bool +} + +func (t testTimeout) Timeout() bool { + return t.timeout +} + +func (t testTimeout) Error() string { + return "test timeout" +} + +var _ = Describe("error", func() { + BeforeEach(func() { + + }) + + AfterEach(func() { + + }) + + It("should retry", func() { + data := map[error]bool{ + io.EOF: true, + io.ErrUnexpectedEOF: true, + nil: false, + context.Canceled: false, + context.DeadlineExceeded: false, + redis.ErrPoolTimeout: true, + errors.New("ERR max number of clients reached"): true, + errors.New("LOADING Redis is loading the dataset in memory"): true, + errors.New("READONLY You can't write against a read only replica"): true, + errors.New("CLUSTERDOWN The cluster is down"): true, + errors.New("TRYAGAIN Command cannot be processed, please try again"): true, + errors.New("other"): false, + } + + for err, expected := range data { + Expect(redis.ShouldRetry(err, false)).To(Equal(expected)) + Expect(redis.ShouldRetry(err, true)).To(Equal(expected)) + } + }) + + It("should retry timeout", func() { + t1 := testTimeout{timeout: true} + Expect(redis.ShouldRetry(t1, true)).To(Equal(true)) + Expect(redis.ShouldRetry(t1, false)).To(Equal(false)) + + t2 := testTimeout{timeout: false} + Expect(redis.ShouldRetry(t2, true)).To(Equal(true)) + Expect(redis.ShouldRetry(t2, false)).To(Equal(true)) + }) +}) diff --git a/export_test.go b/export_test.go index 3f92983d..10d8f23c 100644 --- a/export_test.go +++ b/export_test.go @@ -11,6 +11,8 @@ import ( "github.com/redis/go-redis/v9/internal/pool" ) +var ErrPoolTimeout = pool.ErrPoolTimeout + func (c *baseClient) Pool() pool.Pooler { return c.connPool } @@ -102,3 +104,7 @@ func (c *Ring) ShardByName(name string) *ringShard { func (c *ModuleLoadexConfig) ToArgs() []interface{} { return c.toArgs() } + +func ShouldRetry(err error, retryTimeout bool) bool { + return shouldRetry(err, retryTimeout) +}