* Allow common redis and leveldb connections Prevents multiple reopening of redis and leveldb connections to the same place by sharing connections. Further allows for more configurable redis connection type using the redisURI and a leveldbURI scheme. Signed-off-by: Andrew Thornton <[email protected]> * add unit-test Signed-off-by: Andrew Thornton <[email protected]> * as per @lunny Signed-off-by: Andrew Thornton <[email protected]> * add test Signed-off-by: Andrew Thornton <[email protected]> * Update modules/cache/cache_redis.go * Update modules/queue/queue_disk.go * Update modules/cache/cache_redis.go * Update modules/cache/cache_redis.go * Update modules/queue/unique_queue_disk.go * Update modules/queue/queue_disk.go * Update modules/queue/unique_queue_disk.go * Update modules/session/redis.go Co-authored-by: techknowlogick <[email protected]> Co-authored-by: Lauris BH <[email protected]>
109 lines
2.0 KiB
Go
Vendored
109 lines
2.0 KiB
Go
Vendored
package redis
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
|
|
"github.com/go-redis/redis/v7/internal/pool"
|
|
"github.com/go-redis/redis/v7/internal/proto"
|
|
)
|
|
|
|
var ErrClosed = pool.ErrClosed
|
|
|
|
type Error interface {
|
|
error
|
|
|
|
// RedisError is a no-op function but
|
|
// serves to distinguish types that are Redis
|
|
// errors from ordinary errors: a type is a
|
|
// Redis error if it has a RedisError method.
|
|
RedisError()
|
|
}
|
|
|
|
var _ Error = proto.RedisError("")
|
|
|
|
func isRetryableError(err error, retryTimeout bool) bool {
|
|
switch err {
|
|
case nil, context.Canceled, context.DeadlineExceeded:
|
|
return false
|
|
case io.EOF:
|
|
return true
|
|
}
|
|
if netErr, ok := err.(net.Error); ok {
|
|
if netErr.Timeout() {
|
|
return retryTimeout
|
|
}
|
|
return true
|
|
}
|
|
|
|
s := err.Error()
|
|
if s == "ERR max number of clients reached" {
|
|
return true
|
|
}
|
|
if strings.HasPrefix(s, "LOADING ") {
|
|
return true
|
|
}
|
|
if strings.HasPrefix(s, "READONLY ") {
|
|
return true
|
|
}
|
|
if strings.HasPrefix(s, "CLUSTERDOWN ") {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isRedisError(err error) bool {
|
|
_, ok := err.(proto.RedisError)
|
|
return ok
|
|
}
|
|
|
|
func isBadConn(err error, allowTimeout bool) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
if isRedisError(err) {
|
|
// Close connections in read only state in case domain addr is used
|
|
// and domain resolves to a different Redis Server. See #790.
|
|
return isReadOnlyError(err)
|
|
}
|
|
if allowTimeout {
|
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func isMovedError(err error) (moved bool, ask bool, addr string) {
|
|
if !isRedisError(err) {
|
|
return
|
|
}
|
|
|
|
s := err.Error()
|
|
switch {
|
|
case strings.HasPrefix(s, "MOVED "):
|
|
moved = true
|
|
case strings.HasPrefix(s, "ASK "):
|
|
ask = true
|
|
default:
|
|
return
|
|
}
|
|
|
|
ind := strings.LastIndex(s, " ")
|
|
if ind == -1 {
|
|
return false, false, ""
|
|
}
|
|
addr = s[ind+1:]
|
|
return
|
|
}
|
|
|
|
func isLoadingError(err error) bool {
|
|
return strings.HasPrefix(err.Error(), "LOADING ")
|
|
}
|
|
|
|
func isReadOnlyError(err error) bool {
|
|
return strings.HasPrefix(err.Error(), "READONLY ")
|
|
}
|