Repository: zeromicro/go-zero
Pull request #1514 (2022-02-09 00:09:50)

chore: make error clearer

kevwan: To keep the semantics, I recommend not to export errors.
chenquan: > To keep the semantics, I recommend not to export errors.

fixed.

Patch:
diff --git a/core/discov/config.go b/core/discov/config.go
index c1f6b7b1..1557b4f8 100644
--- a/core/discov/config.go
+++ b/core/discov/config.go
@@ -2,6 +2,13 @@ package discov
 
 import "errors"
 
+var (
+	// errEmptyEtcdHosts indicates that etcd hosts are empty.
+	errEmptyEtcdHosts = errors.New("empty etcd hosts")
+	// errEmptyEtcdKey indicates that etcd key is empty.
+	errEmptyEtcdKey = errors.New("empty etcd key")
+)
+
 // EtcdConf is the config item with the given key on etcd.
 type EtcdConf struct {
 	Hosts              []string
@@ -27,9 +34,9 @@ func (c EtcdConf) HasTLS() bool {
 // Validate validates c.
 func (c EtcdConf) Validate() error {
 	if len(c.Hosts) == 0 {
-		return errors.New("empty etcd hosts")
+		return errEmptyEtcdHosts
 	} else if len(c.Key) == 0 {
-		return errors.New("empty etcd key")
+		return errEmptyEtcdKey
 	} else {
 		return nil
 	}
diff --git a/core/filex/rangereader.go b/core/filex/rangereader.go
index cd69f678..0a962e51 100644
--- a/core/filex/rangereader.go
+++ b/core/filex/rangereader.go
@@ -5,6 +5,9 @@ import (
 	"os"
 )
 
+// errExceedFileSize indicates that the file size is exceeded.
+var errExceedFileSize = errors.New("exceed file size")
+
 // A RangeReader is used to read a range of content from a file.
 type RangeReader struct {
 	file  *os.File
@@ -29,7 +32,7 @@ func (rr *RangeReader) Read(p []byte) (n int, err error) {
 	}
 
 	if rr.stop < rr.start || rr.start >= stat.Size() {
-		return 0, errors.New("exceed file size")
+		return 0, errExceedFileSize
 	}
 
 	if rr.stop-rr.start < int64(len(p)) {
diff --git a/core/jsonx/json.go b/core/jsonx/json.go
index c4f60b68..176e30a0 100644
--- a/core/jsonx/json.go
+++ b/core/jsonx/json.go
@@ -51,5 +51,5 @@ func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error {
 }
 
 func formatError(v string, err error) error {
-	return fmt.Errorf("string: `%s`, error: `%s`", v, err.Error())
+	return fmt.Errorf("string: `%s`, error: `%w`", v, err)
 }
diff --git a/core/stores/redis/hook.go b/core/stores/redis/hook.go
new file mode 100644
index 00000000..a0013c34
--- /dev/null
+++ b/core/stores/redis/hook.go
@@ -0,0 +1,83 @@
+package redis
+
+import (
+	"context"
+	"strings"
+	"time"
+
+	red "github.com/go-redis/redis/v8"
+	"github.com/zeromicro/go-zero/core/logx"
+	"github.com/zeromicro/go-zero/core/mapping"
+	"github.com/zeromicro/go-zero/core/timex"
+)
+
+var (
+	startTimeKey = contextKey("startTime")
+	durationHook = hook{}
+)
+
+type (
+	contextKey string
+	hook       struct{}
+)
+
+func (h hook) BeforeProcess(ctx context.Context, _ red.Cmder) (context.Context, error) {
+	return context.WithValue(ctx, startTimeKey, timex.Now()), nil
+}
+
+func (h hook) AfterProcess(ctx context.Context, cmd red.Cmder) error {
+	val := ctx.Value(startTimeKey)
+	if val == nil {
+		return nil
+	}
+
+	start, ok := val.(time.Duration)
+	if !ok {
+		return nil
+	}
+
+	duration := timex.Since(start)
+	if duration > slowThreshold.Load() {
+		logDuration(ctx, cmd, duration)
+	}
+
+	return nil
+}
+
+func (h hook) BeforeProcessPipeline(ctx context.Context, _ []red.Cmder) (context.Context, error) {
+	return context.WithValue(ctx, startTimeKey, timex.Now()), nil
+}
+
+func (h hook) AfterProcessPipeline(ctx context.Context, cmds []red.Cmder) error {
+	if len(cmds) == 0 {
+		return nil
+	}
+
+	val := ctx.Value(startTimeKey)
+	if val == nil {
+		return nil
+	}
+
+	start, ok := val.(time.Duration)
+	if !ok {
+		return nil
+	}
+
+	duration := timex.Since(start)
+	if duration > slowThreshold.Load()*time.Duration(len(cmds)) {
+		logDuration(ctx, cmds[0], duration)
+	}
+
+	return nil
+}
+
+func logDuration(ctx context.Context, cmd red.Cmder, duration time.Duration) {
+	var buf strings.Builder
+	for i, arg := range cmd.Args() {
+		if i > 0 {
+			buf.WriteByte(' ')
+		}
+		buf.WriteString(mapping.Repr(arg))
+	}
+	logx.WithContext(ctx).WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
+}
diff --git a/core/stores/redis/process.go b/core/stores/redis/process.go
deleted file mode 100644
index 479095e9..00000000
--- a/core/stores/redis/process.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package redis
-
-import (
-	"strings"
-
-	red "github.com/go-redis/redis"
-	"github.com/zeromicro/go-zero/core/logx"
-	"github.com/zeromicro/go-zero/core/mapping"
-	"github.com/zeromicro/go-zero/core/timex"
-)
-
-func checkDuration(proc func(red.Cmder) error) func(red.Cmder) error {
-	return func(cmd red.Cmder) error {
-		start := timex.Now()
-
-		defer func() {
-			duration := timex.Since(start)
-			if duration > slowThreshold.Load() {
-				var buf strings.Builder
-				for i, arg := range cmd.Args() {
-					if i > 0 {
-						buf.WriteByte(' ')
-					}
-					buf.WriteString(mapping.Repr(arg))
-				}
-				logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
-			}
-		}()
-
-		return proc(cmd)
-	}
-}
diff --git a/core/stores/redis/redis.go b/core/stores/redis/redis.go
index 2479fc49..b713cb49 100644
--- a/core/stores/redis/redis.go
+++ b/core/stores/redis/redis.go
@@ -1,12 +1,13 @@
 package redis
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"strconv"
 	"time"
 
-	red "github.com/go-redis/redis"
+	red "github.com/go-redis/redis/v8"
 	"github.com/zeromicro/go-zero/core/breaker"
 	"github.com/zeromicro/go-zero/core/mapping"
 	"github.com/zeromicro/go-zero/core/syncx"
@@ -93,29 +94,20 @@ func New(addr string, opts ...Option) *Redis {
 	return r
 }
 
-// NewRedis returns a Redis.
-// Deprecated: use New instead, will be removed in v2.
-func NewRedis(redisAddr, redisType string, redisPass ...string) *Redis {
-	var opts []Option
-	if redisType == ClusterType {
-		opts = append(opts, Cluster())
-	}
-	for _, v := range redisPass {
-		opts = append(opts, WithPass(v))
-	}
-
-	return New(redisAddr, opts...)
+// BitCount is redis bitcount command implementation.
+func (s *Redis) BitCount(key string, start, end int64) (int64, error) {
+	return s.BitCountCtx(context.Background(), key, start, end)
 }
 
-// BitCount is redis bitcount command implementation.
-func (s *Redis) BitCount(key string, start, end int64) (val int64, err error) {
+// BitCountCtx is redis bitcount command implementation.
+func (s *Redis) BitCountCtx(ctx context.Context, key string, start, end int64) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.BitCount(key, &red.BitCount{
+		val, err = conn.BitCount(ctx, key, &red.BitCount{
 			Start: start,
 			End:   end,
 		}).Result()
@@ -126,14 +118,19 @@ func (s *Redis) BitCount(key string, start, end int64) (val int64, err error) {
 }
 
 // BitOpAnd is redis bit operation (and) command implementation.
-func (s *Redis) BitOpAnd(destKey string, keys ...string) (val int64, err error) {
+func (s *Redis) BitOpAnd(destKey string, keys ...string) (int64, error) {
+	return s.BitOpAndCtx(context.Background(), destKey, keys...)
+}
+
+// BitOpAndCtx is redis bit operation (and) command implementation.
+func (s *Redis) BitOpAndCtx(ctx context.Context, destKey string, keys ...string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.BitOpAnd(destKey, keys...).Result()
+		val, err = conn.BitOpAnd(ctx, destKey, keys...).Result()
 		return err
 	}, acceptable)
 
@@ -141,14 +138,19 @@ func (s *Redis) BitOpAnd(destKey string, keys ...string) (val int64, err error)
 }
 
 // BitOpNot is redis bit operation (not) command implementation.
-func (s *Redis) BitOpNot(destKey, key string) (val int64, err error) {
+func (s *Redis) BitOpNot(destKey, key string) (int64, error) {
+	return s.BitOpNotCtx(context.Background(), destKey, key)
+}
+
+// BitOpNotCtx is redis bit operation (not) command implementation.
+func (s *Redis) BitOpNotCtx(ctx context.Context, destKey, key string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.BitOpNot(destKey, key).Result()
+		val, err = conn.BitOpNot(ctx, destKey, key).Result()
 		return err
 	}, acceptable)
 
@@ -156,14 +158,19 @@ func (s *Redis) BitOpNot(destKey, key string) (val int64, err error) {
 }
 
 // BitOpOr is redis bit operation (or) command implementation.
-func (s *Redis) BitOpOr(destKey string, keys ...string) (val int64, err error) {
+func (s *Redis) BitOpOr(destKey string, keys ...string) (int64, error) {
+	return s.BitOpOrCtx(context.Background(), destKey, keys...)
+}
+
+// BitOpOrCtx is redis bit operation (or) command implementation.
+func (s *Redis) BitOpOrCtx(ctx context.Context, destKey string, keys ...string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.BitOpOr(destKey, keys...).Result()
+		val, err = conn.BitOpOr(ctx, destKey, keys...).Result()
 		return err
 	}, acceptable)
 
@@ -171,14 +178,19 @@ func (s *Redis) BitOpOr(destKey string, keys ...string) (val int64, err error) {
 }
 
 // BitOpXor is redis bit operation (xor) command implementation.
-func (s *Redis) BitOpXor(destKey string, keys ...string) (val int64, err error) {
+func (s *Redis) BitOpXor(destKey string, keys ...string) (int64, error) {
+	return s.BitOpXorCtx(context.Background(), destKey, keys...)
+}
+
+// BitOpXorCtx is redis bit operation (xor) command implementation.
+func (s *Redis) BitOpXorCtx(ctx context.Context, destKey string, keys ...string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.BitOpXor(destKey, keys...).Result()
+		val, err = conn.BitOpXor(ctx, destKey, keys...).Result()
 		return err
 	}, acceptable)
 
@@ -186,14 +198,19 @@ func (s *Redis) BitOpXor(destKey string, keys ...string) (val int64, err error)
 }
 
 // BitPos is redis bitpos command implementation.
-func (s *Redis) BitPos(key string, bit, start, end int64) (val int64, err error) {
+func (s *Redis) BitPos(key string, bit, start, end int64) (int64, error) {
+	return s.BitPosCtx(context.Background(), key, bit, start, end)
+}
+
+// BitPosCtx is redis bitpos command implementation.
+func (s *Redis) BitPosCtx(ctx context.Context, key string, bit, start, end int64) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.BitPos(key, bit, start, end).Result()
+		val, err = conn.BitPos(ctx, key, bit, start, end).Result()
 		return err
 	}, acceptable)
 
@@ -202,12 +219,18 @@ func (s *Redis) BitPos(key string, bit, start, end int64) (val int64, err error)
 
 // Blpop uses passed in redis connection to execute blocking queries.
 // Doesn't benefit from pooling redis connections of blocking queries
-func (s *Redis) Blpop(redisNode RedisNode, key string) (string, error) {
-	if redisNode == nil {
+func (s *Redis) Blpop(node RedisNode, key string) (string, error) {
+	return s.BlpopCtx(context.Background(), node, key)
+}
+
+// BlpopCtx uses passed in redis connection to execute blocking queries.
+// Doesn't benefit from pooling redis connections of blocking queries
+func (s *Redis) BlpopCtx(ctx context.Context, node RedisNode, key string) (string, error) {
+	if node == nil {
 		return "", ErrNilNode
 	}
 
-	vals, err := redisNode.BLPop(blockingQueryTimeout, key).Result()
+	vals, err := node.BLPop(ctx, blockingQueryTimeout, key).Result()
 	if err != nil {
 		return "", err
 	}
@@ -221,12 +244,18 @@ func (s *Redis) Blpop(redisNode RedisNode, key string) (string, error) {
 
 // BlpopEx uses passed in redis connection to execute blpop command.
 // The difference against Blpop is that this method returns a bool to indicate success.
-func (s *Redis) BlpopEx(redisNode RedisNode, key string) (string, bool, error) {
-	if redisNode == nil {
+func (s *Redis) BlpopEx(node RedisNode, key string) (string, bool, error) {
+	return s.BlpopExCtx(context.Background(), node, key)
+}
+
+// BlpopExCtx uses passed in redis connection to execute blpop command.
+// The difference against Blpop is that this method returns a bool to indicate success.
+func (s *Redis) BlpopExCtx(ctx context.Context, node RedisNode, key string) (string, bool, error) {
+	if node == nil {
 		return "", false, ErrNilNode
 	}
 
-	vals, err := redisNode.BLPop(blockingQueryTimeout, key).Result()
+	vals, err := node.BLPop(ctx, blockingQueryTimeout, key).Result()
 	if err != nil {
 		return "", false, err
 	}
@@ -239,14 +268,19 @@ func (s *Redis) BlpopEx(redisNode RedisNode, key string) (string, bool, error) {
 }
 
 // Decr is the implementation of redis decr command.
-func (s *Redis) Decr(key string) (val int64, err error) {
+func (s *Redis) Decr(key string) (int64, error) {
+	return s.DecrCtx(context.Background(), key)
+}
+
+// DecrCtx is the implementation of redis decr command.
+func (s *Redis) DecrCtx(ctx context.Context, key string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.Decr(key).Result()
+		val, err = conn.Decr(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -254,14 +288,19 @@ func (s *Redis) Decr(key string) (val int64, err error) {
 }
 
 // Decrby is the implementation of redis decrby command.
-func (s *Redis) Decrby(key string, increment int64) (val int64, err error) {
+func (s *Redis) Decrby(key string, decrement int64) (int64, error) {
+	return s.DecrbyCtx(context.Background(), key, decrement)
+}
+
+// DecrbyCtx is the implementation of redis decrby command.
+func (s *Redis) DecrbyCtx(ctx context.Context, key string, decrement int64) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.DecrBy(key, increment).Result()
+		val, err = conn.DecrBy(ctx, key, decrement).Result()
 		return err
 	}, acceptable)
 
@@ -269,14 +308,19 @@ func (s *Redis) Decrby(key string, increment int64) (val int64, err error) {
 }
 
 // Del deletes keys.
-func (s *Redis) Del(keys ...string) (val int, err error) {
+func (s *Redis) Del(keys ...string) (int, error) {
+	return s.DelCtx(context.Background(), keys...)
+}
+
+// DelCtx deletes keys.
+func (s *Redis) DelCtx(ctx context.Context, keys ...string) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.Del(keys...).Result()
+		v, err := conn.Del(ctx, keys...).Result()
 		if err != nil {
 			return err
 		}
@@ -289,14 +333,20 @@ func (s *Redis) Del(keys ...string) (val int, err error) {
 }
 
 // Eval is the implementation of redis eval command.
-func (s *Redis) Eval(script string, keys []string, args ...interface{}) (val interface{}, err error) {
+func (s *Redis) Eval(script string, keys []string, args ...interface{}) (interface{}, error) {
+	return s.EvalCtx(context.Background(), script, keys, args...)
+}
+
+// EvalCtx is the implementation of redis eval command.
+func (s *Redis) EvalCtx(ctx context.Context, script string, keys []string,
+	args ...interface{}) (val interface{}, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.Eval(script, keys, args...).Result()
+		val, err = conn.Eval(ctx, script, keys, args...).Result()
 		return err
 	}, acceptable)
 
@@ -304,14 +354,20 @@ func (s *Redis) Eval(script string, keys []string, args ...interface{}) (val int
 }
 
 // EvalSha is the implementation of redis evalsha command.
-func (s *Redis) EvalSha(sha string, keys []string, args ...interface{}) (val interface{}, err error) {
+func (s *Redis) EvalSha(sha string, keys []string, args ...interface{}) (interface{}, error) {
+	return s.EvalShaCtx(context.Background(), sha, keys, args...)
+}
+
+// EvalShaCtx is the implementation of redis evalsha command.
+func (s *Redis) EvalShaCtx(ctx context.Context, sha string, keys []string,
+	args ...interface{}) (val interface{}, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.EvalSha(sha, keys, args...).Result()
+		val, err = conn.EvalSha(ctx, sha, keys, args...).Result()
 		return err
 	}, acceptable)
 
@@ -319,14 +375,19 @@ func (s *Redis) EvalSha(sha string, keys []string, args ...interface{}) (val int
 }
 
 // Exists is the implementation of redis exists command.
-func (s *Redis) Exists(key string) (val bool, err error) {
+func (s *Redis) Exists(key string) (bool, error) {
+	return s.ExistsCtx(context.Background(), key)
+}
+
+// ExistsCtx is the implementation of redis exists command.
+func (s *Redis) ExistsCtx(ctx context.Context, key string) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.Exists(key).Result()
+		v, err := conn.Exists(ctx, key).Result()
 		if err != nil {
 			return err
 		}
@@ -340,37 +401,53 @@ func (s *Redis) Exists(key string) (val bool, err error) {
 
 // Expire is the implementation of redis expire command.
 func (s *Redis) Expire(key string, seconds int) error {
+	return s.ExpireCtx(context.Background(), key, seconds)
+}
+
+// ExpireCtx is the implementation of redis expire command.
+func (s *Redis) ExpireCtx(ctx context.Context, key string, seconds int) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		return conn.Expire(key, time.Duration(seconds)*time.Second).Err()
+		return conn.Expire(ctx, key, time.Duration(seconds)*time.Second).Err()
 	}, acceptable)
 }
 
 // Expireat is the implementation of redis expireat command.
 func (s *Redis) Expireat(key string, expireTime int64) error {
+	return s.ExpireatCtx(context.Background(), key, expireTime)
+}
+
+// ExpireatCtx is the implementation of redis expireat command.
+func (s *Redis) ExpireatCtx(ctx context.Context, key string, expireTime int64) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		return conn.ExpireAt(key, time.Unix(expireTime, 0)).Err()
+		return conn.ExpireAt(ctx, key, time.Unix(expireTime, 0)).Err()
 	}, acceptable)
 }
 
 // GeoAdd is the implementation of redis geoadd command.
-func (s *Redis) GeoAdd(key string, geoLocation ...*GeoLocation) (val int64, err error) {
+func (s *Redis) GeoAdd(key string, geoLocation ...*GeoLocation) (int64, error) {
+	return s.GeoAddCtx(context.Background(), key, geoLocation...)
+}
+
+// GeoAddCtx is the implementation of redis geoadd command.
+func (s *Redis) GeoAddCtx(ctx context.Context, key string, geoLocation ...*GeoLocation) (
+	val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GeoAdd(key, geoLocation...).Result()
+		v, err := conn.GeoAdd(ctx, key, geoLocation...).Result()
 		if err != nil {
 			return err
 		}
@@ -378,18 +455,25 @@ func (s *Redis) GeoAdd(key string, geoLocation ...*GeoLocation) (val int64, err
 		val = v
 		return nil
 	}, acceptable)
+
 	return
 }
 
 // GeoDist is the implementation of redis geodist command.
-func (s *Redis) GeoDist(key, member1, member2, unit string) (val float64, err error) {
+func (s *Redis) GeoDist(key, member1, member2, unit string) (float64, error) {
+	return s.GeoDistCtx(context.Background(), key, member1, member2, unit)
+}
+
+// GeoDistCtx is the implementation of redis geodist command.
+func (s *Redis) GeoDistCtx(ctx context.Context, key, member1, member2, unit string) (
+	val float64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GeoDist(key, member1, member2, unit).Result()
+		v, err := conn.GeoDist(ctx, key, member1, member2, unit).Result()
 		if err != nil {
 			return err
 		}
@@ -397,18 +481,25 @@ func (s *Redis) GeoDist(key, member1, member2, unit string) (val float64, err er
 		val = v
 		return nil
 	}, acceptable)
+
 	return
 }
 
 // GeoHash is the implementation of redis geohash command.
-func (s *Redis) GeoHash(key string, members ...string) (val []string, err error) {
+func (s *Redis) GeoHash(key string, members ...string) ([]string, error) {
+	return s.GeoHashCtx(context.Background(), key, members...)
+}
+
+// GeoHashCtx is the implementation of redis geohash command.
+func (s *Redis) GeoHashCtx(ctx context.Context, key string, members ...string) (
+	val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GeoHash(key, members...).Result()
+		v, err := conn.GeoHash(ctx, key, members...).Result()
 		if err != nil {
 			return err
 		}
@@ -416,18 +507,26 @@ func (s *Redis) GeoHash(key string, members ...string) (val []string, err error)
 		val = v
 		return nil
 	}, acceptable)
+
 	return
 }
 
 // GeoRadius is the implementation of redis georadius command.
-func (s *Redis) GeoRadius(key string, longitude, latitude float64, query *GeoRadiusQuery) (val []GeoLocation, err error) {
+func (s *Redis) GeoRadius(key string, longitude, latitude float64, query *GeoRadiusQuery) (
+	[]GeoLocation, error) {
+	return s.GeoRadiusCtx(context.Background(), key, longitude, latitude, query)
+}
+
+// GeoRadiusCtx is the implementation of redis georadius command.
+func (s *Redis) GeoRadiusCtx(ctx context.Context, key string, longitude, latitude float64,
+	query *GeoRadiusQuery) (val []GeoLocation, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GeoRadius(key, longitude, latitude, query).Result()
+		v, err := conn.GeoRadius(ctx, key, longitude, latitude, query).Result()
 		if err != nil {
 			return err
 		}
@@ -435,18 +534,25 @@ func (s *Redis) GeoRadius(key string, longitude, latitude float64, query *GeoRad
 		val = v
 		return nil
 	}, acceptable)
+
 	return
 }
 
 // GeoRadiusByMember is the implementation of redis georadiusbymember command.
-func (s *Redis) GeoRadiusByMember(key, member string, query *GeoRadiusQuery) (val []GeoLocation, err error) {
+func (s *Redis) GeoRadiusByMember(key, member string, query *GeoRadiusQuery) ([]GeoLocation, error) {
+	return s.GeoRadiusByMemberCtx(context.Background(), key, member, query)
+}
+
+// GeoRadiusByMemberCtx is the implementation of redis georadiusbymember command.
+func (s *Redis) GeoRadiusByMemberCtx(ctx context.Context, key, member string,
+	query *GeoRadiusQuery) (val []GeoLocation, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GeoRadiusByMember(key, member, query).Result()
+		v, err := conn.GeoRadiusByMember(ctx, key, member, query).Result()
 		if err != nil {
 			return err
 		}
@@ -454,18 +560,25 @@ func (s *Redis) GeoRadiusByMember(key, member string, query *GeoRadiusQuery) (va
 		val = v
 		return nil
 	}, acceptable)
+
 	return
 }
 
 // GeoPos is the implementation of redis geopos command.
-func (s *Redis) GeoPos(key string, members ...string) (val []*GeoPos, err error) {
+func (s *Redis) GeoPos(key string, members ...string) ([]*GeoPos, error) {
+	return s.GeoPosCtx(context.Background(), key, members...)
+}
+
+// GeoPosCtx is the implementation of redis geopos command.
+func (s *Redis) GeoPosCtx(ctx context.Context, key string, members ...string) (
+	val []*GeoPos, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GeoPos(key, members...).Result()
+		v, err := conn.GeoPos(ctx, key, members...).Result()
 		if err != nil {
 			return err
 		}
@@ -473,18 +586,24 @@ func (s *Redis) GeoPos(key string, members ...string) (val []*GeoPos, err error)
 		val = v
 		return nil
 	}, acceptable)
+
 	return
 }
 
 // Get is the implementation of redis get command.
-func (s *Redis) Get(key string) (val string, err error) {
+func (s *Redis) Get(key string) (string, error) {
+	return s.GetCtx(context.Background(), key)
+}
+
+// GetCtx is the implementation of redis get command.
+func (s *Redis) GetCtx(ctx context.Context, key string) (val string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		if val, err = conn.Get(key).Result(); err == red.Nil {
+		if val, err = conn.Get(ctx, key).Result(); err == red.Nil {
 			return nil
 		} else if err != nil {
 			return err
@@ -497,14 +616,19 @@ func (s *Redis) Get(key string) (val string, err error) {
 }
 
 // GetBit is the implementation of redis getbit command.
-func (s *Redis) GetBit(key string, offset int64) (val int, err error) {
+func (s *Redis) GetBit(key string, offset int64) (int, error) {
+	return s.GetBitCtx(context.Background(), key, offset)
+}
+
+// GetBitCtx is the implementation of redis getbit command.
+func (s *Redis) GetBitCtx(ctx context.Context, key string, offset int64) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.GetBit(key, offset).Result()
+		v, err := conn.GetBit(ctx, key, offset).Result()
 		if err != nil {
 			return err
 		}
@@ -517,14 +641,19 @@ func (s *Redis) GetBit(key string, offset int64) (val int, err error) {
 }
 
 // Hdel is the implementation of redis hdel command.
-func (s *Redis) Hdel(key string, fields ...string) (val bool, err error) {
+func (s *Redis) Hdel(key string, fields ...string) (bool, error) {
+	return s.HdelCtx(context.Background(), key, fields...)
+}
+
+// HdelCtx is the implementation of redis hdel command.
+func (s *Redis) HdelCtx(ctx context.Context, key string, fields ...string) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.HDel(key, fields...).Result()
+		v, err := conn.HDel(ctx, key, fields...).Result()
 		if err != nil {
 			return err
 		}
@@ -537,14 +666,19 @@ func (s *Redis) Hdel(key string, fields ...string) (val bool, err error) {
 }
 
 // Hexists is the implementation of redis hexists command.
-func (s *Redis) Hexists(key, field string) (val bool, err error) {
+func (s *Redis) Hexists(key, field string) (bool, error) {
+	return s.HexistsCtx(context.Background(), key, field)
+}
+
+// HexistsCtx is the implementation of redis hexists command.
+func (s *Redis) HexistsCtx(ctx context.Context, key, field string) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.HExists(key, field).Result()
+		val, err = conn.HExists(ctx, key, field).Result()
 		return err
 	}, acceptable)
 
@@ -552,14 +686,19 @@ func (s *Redis) Hexists(key, field string) (val bool, err error) {
 }
 
 // Hget is the implementation of redis hget command.
-func (s *Redis) Hget(key, field string) (val string, err error) {
+func (s *Redis) Hget(key, field string) (string, error) {
+	return s.HgetCtx(context.Background(), key, field)
+}
+
+// HgetCtx is the implementation of redis hget command.
+func (s *Redis) HgetCtx(ctx context.Context, key, field string) (val string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.HGet(key, field).Result()
+		val, err = conn.HGet(ctx, key, field).Result()
 		return err
 	}, acceptable)
 
@@ -567,14 +706,19 @@ func (s *Redis) Hget(key, field string) (val string, err error) {
 }
 
 // Hgetall is the implementation of redis hgetall command.
-func (s *Redis) Hgetall(key string) (val map[string]string, err error) {
+func (s *Redis) Hgetall(key string) (map[string]string, error) {
+	return s.HgetallCtx(context.Background(), key)
+}
+
+// HgetallCtx is the implementation of redis hgetall command.
+func (s *Redis) HgetallCtx(ctx context.Context, key string) (val map[string]string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.HGetAll(key).Result()
+		val, err = conn.HGetAll(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -582,14 +726,19 @@ func (s *Redis) Hgetall(key string) (val map[string]string, err error) {
 }
 
 // Hincrby is the implementation of redis hincrby command.
-func (s *Redis) Hincrby(key, field string, increment int) (val int, err error) {
+func (s *Redis) Hincrby(key, field string, increment int) (int, error) {
+	return s.HincrbyCtx(context.Background(), key, field, increment)
+}
+
+// HincrbyCtx is the implementation of redis hincrby command.
+func (s *Redis) HincrbyCtx(ctx context.Context, key, field string, increment int) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.HIncrBy(key, field, int64(increment)).Result()
+		v, err := conn.HIncrBy(ctx, key, field, int64(increment)).Result()
 		if err != nil {
 			return err
 		}
@@ -602,14 +751,19 @@ func (s *Redis) Hincrby(key, field string, increment int) (val int, err error) {
 }
 
 // Hkeys is the implementation of redis hkeys command.
-func (s *Redis) Hkeys(key string) (val []string, err error) {
+func (s *Redis) Hkeys(key string) ([]string, error) {
+	return s.HkeysCtx(context.Background(), key)
+}
+
+// HkeysCtx is the implementation of redis hkeys command.
+func (s *Redis) HkeysCtx(ctx context.Context, key string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.HKeys(key).Result()
+		val, err = conn.HKeys(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -617,14 +771,19 @@ func (s *Redis) Hkeys(key string) (val []string, err error) {
 }
 
 // Hlen is the implementation of redis hlen command.
-func (s *Redis) Hlen(key string) (val int, err error) {
+func (s *Redis) Hlen(key string) (int, error) {
+	return s.HlenCtx(context.Background(), key)
+}
+
+// HlenCtx is the implementation of redis hlen command.
+func (s *Redis) HlenCtx(ctx context.Context, key string) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.HLen(key).Result()
+		v, err := conn.HLen(ctx, key).Result()
 		if err != nil {
 			return err
 		}
@@ -637,14 +796,19 @@ func (s *Redis) Hlen(key string) (val int, err error) {
 }
 
 // Hmget is the implementation of redis hmget command.
-func (s *Redis) Hmget(key string, fields ...string) (val []string, err error) {
+func (s *Redis) Hmget(key string, fields ...string) ([]string, error) {
+	return s.HmgetCtx(context.Background(), key, fields...)
+}
+
+// HmgetCtx is the implementation of redis hmget command.
+func (s *Redis) HmgetCtx(ctx context.Context, key string, fields ...string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.HMGet(key, fields...).Result()
+		v, err := conn.HMGet(ctx, key, fields...).Result()
 		if err != nil {
 			return err
 		}
@@ -658,25 +822,35 @@ func (s *Redis) Hmget(key string, fields ...string) (val []string, err error) {
 
 // Hset is the implementation of redis hset command.
 func (s *Redis) Hset(key, field, value string) error {
+	return s.HsetCtx(context.Background(), key, field, value)
+}
+
+// HsetCtx is the implementation of redis hset command.
+func (s *Redis) HsetCtx(ctx context.Context, key, field, value string) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		return conn.HSet(key, field, value).Err()
+		return conn.HSet(ctx, key, field, value).Err()
 	}, acceptable)
 }
 
 // Hsetnx is the implementation of redis hsetnx command.
-func (s *Redis) Hsetnx(key, field, value string) (val bool, err error) {
+func (s *Redis) Hsetnx(key, field, value string) (bool, error) {
+	return s.HsetnxCtx(context.Background(), key, field, value)
+}
+
+// HsetnxCtx is the implementation of redis hsetnx command.
+func (s *Redis) HsetnxCtx(ctx context.Context, key, field, value string) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.HSetNX(key, field, value).Result()
+		val, err = conn.HSetNX(ctx, key, field, value).Result()
 		return err
 	}, acceptable)
 
@@ -685,6 +859,11 @@ func (s *Redis) Hsetnx(key, field, value string) (val bool, err error) {
 
 // Hmset is the implementation of redis hmset command.
 func (s *Redis) Hmset(key string, fieldsAndValues map[string]string) error {
+	return s.HmsetCtx(context.Background(), key, fieldsAndValues)
+}
+
+// HmsetCtx is the implementation of redis hmset command.
+func (s *Redis) HmsetCtx(ctx context.Context, key string, fieldsAndValues map[string]string) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
@@ -696,19 +875,26 @@ func (s *Redis) Hmset(key string, fieldsAndValues map[string]string) error {
 			vals[k] = v
 		}
 
-		return conn.HMSet(key, vals).Err()
+		return conn.HMSet(ctx, key, vals).Err()
 	}, acceptable)
 }
 
 // Hscan is the implementation of redis hscan command.
-func (s *Redis) Hscan(key string, cursor uint64, match string, count int64) (keys []string, cur uint64, err error) {
+func (s *Redis) Hscan(key string, cursor uint64, match string, count int64) (
+	keys []string, cur uint64, err error) {
+	return s.HscanCtx(context.Background(), key, cursor, match, count)
+}
+
+// HscanCtx is the implementation of redis hscan command.
+func (s *Redis) HscanCtx(ctx context.Context, key string, cursor uint64, match string, count int64) (
+	keys []string, cur uint64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		keys, cur, err = conn.HScan(key, cursor, match, count).Result()
+		keys, cur, err = conn.HScan(ctx, key, cursor, match, count).Result()
 		return err
 	}, acceptable)
 
@@ -716,14 +902,19 @@ func (s *Redis) Hscan(key string, cursor uint64, match string, count int64) (key
 }
 
 // Hvals is the implementation of redis hvals command.
-func (s *Redis) Hvals(key string) (val []string, err error) {
+func (s *Redis) Hvals(key string) ([]string, error) {
+	return s.HvalsCtx(context.Background(), key)
+}
+
+// HvalsCtx is the implementation of redis hvals command.
+func (s *Redis) HvalsCtx(ctx context.Context, key string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.HVals(key).Result()
+		val, err = conn.HVals(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -731,14 +922,19 @@ func (s *Redis) Hvals(key string) (val []string, err error) {
 }
 
 // Incr is the implementation of redis incr command.
-func (s *Redis) Incr(key string) (val int64, err error) {
+func (s *Redis) Incr(key string) (int64, error) {
+	return s.IncrCtx(context.Background(), key)
+}
+
+// IncrCtx is the implementation of redis incr command.
+func (s *Redis) IncrCtx(ctx context.Context, key string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.Incr(key).Result()
+		val, err = conn.Incr(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -746,14 +942,19 @@ func (s *Redis) Incr(key string) (val int64, err error) {
 }
 
 // Incrby is the implementation of redis incrby command.
-func (s *Redis) Incrby(key string, increment int64) (val int64, err error) {
+func (s *Redis) Incrby(key string, increment int64) (int64, error) {
+	return s.IncrbyCtx(context.Background(), key, increment)
+}
+
+// IncrbyCtx is the implementation of redis incrby command.
+func (s *Redis) IncrbyCtx(ctx context.Context, key string, increment int64) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.IncrBy(key, int64(increment)).Result()
+		val, err = conn.IncrBy(ctx, key, increment).Result()
 		return err
 	}, acceptable)
 
@@ -761,14 +962,19 @@ func (s *Redis) Incrby(key string, increment int64) (val int64, err error) {
 }
 
 // Keys is the implementation of redis keys command.
-func (s *Redis) Keys(pattern string) (val []string, err error) {
+func (s *Redis) Keys(pattern string) ([]string, error) {
+	return s.KeysCtx(context.Background(), pattern)
+}
+
+// KeysCtx is the implementation of redis keys command.
+func (s *Redis) KeysCtx(ctx context.Context, pattern string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.Keys(pattern).Result()
+		val, err = conn.Keys(ctx, pattern).Result()
 		return err
 	}, acceptable)
 
@@ -776,14 +982,19 @@ func (s *Redis) Keys(pattern string) (val []string, err error) {
 }
 
 // Llen is the implementation of redis llen command.
-func (s *Redis) Llen(key string) (val int, err error) {
+func (s *Redis) Llen(key string) (int, error) {
+	return s.LlenCtx(context.Background(), key)
+}
+
+// LlenCtx is the implementation of redis llen command.
+func (s *Redis) LlenCtx(ctx context.Context, key string) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.LLen(key).Result()
+		v, err := conn.LLen(ctx, key).Result()
 		if err != nil {
 			return err
 		}
@@ -796,14 +1007,19 @@ func (s *Redis) Llen(key string) (val int, err error) {
 }
 
 // Lindex is the implementation of redis lindex command.
-func (s *Redis) Lindex(key string, index int64) (val string, err error) {
+func (s *Redis) Lindex(key string, index int64) (string, error) {
+	return s.LindexCtx(context.Background(), key, index)
+}
+
+// LindexCtx is the implementation of redis lindex command.
+func (s *Redis) LindexCtx(ctx context.Context, key string, index int64) (val string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.LIndex(key, index).Result()
+		val, err = conn.LIndex(ctx, key, index).Result()
 		return err
 	}, acceptable)
 
@@ -811,14 +1027,19 @@ func (s *Redis) Lindex(key string, index int64) (val string, err error) {
 }
 
 // Lpop is the implementation of redis lpop command.
-func (s *Redis) Lpop(key string) (val string, err error) {
+func (s *Redis) Lpop(key string) (string, error) {
+	return s.LpopCtx(context.Background(), key)
+}
+
+// LpopCtx is the implementation of redis lpop command.
+func (s *Redis) LpopCtx(ctx context.Context, key string) (val string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.LPop(key).Result()
+		val, err = conn.LPop(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -826,14 +1047,19 @@ func (s *Redis) Lpop(key string) (val string, err error) {
 }
 
 // Lpush is the implementation of redis lpush command.
-func (s *Redis) Lpush(key string, values ...interface{}) (val int, err error) {
+func (s *Redis) Lpush(key string, values ...interface{}) (int, error) {
+	return s.LpushCtx(context.Background(), key, values...)
+}
+
+// LpushCtx is the implementation of redis lpush command.
+func (s *Redis) LpushCtx(ctx context.Context, key string, values ...interface{}) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.LPush(key, values...).Result()
+		v, err := conn.LPush(ctx, key, values...).Result()
 		if err != nil {
 			return err
 		}
@@ -846,14 +1072,19 @@ func (s *Redis) Lpush(key string, values ...interface{}) (val int, err error) {
 }
 
 // Lrange is the implementation of redis lrange command.
-func (s *Redis) Lrange(key string, start, stop int) (val []string, err error) {
+func (s *Redis) Lrange(key string, start, stop int) ([]string, error) {
+	return s.LrangeCtx(context.Background(), key, start, stop)
+}
+
+// LrangeCtx is the implementation of redis lrange command.
+func (s *Redis) LrangeCtx(ctx context.Context, key string, start, stop int) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.LRange(key, int64(start), int64(stop)).Result()
+		val, err = conn.LRange(ctx, key, int64(start), int64(stop)).Result()
 		return err
 	}, acceptable)
 
@@ -861,14 +1092,19 @@ func (s *Redis) Lrange(key string, start, stop int) (val []string, err error) {
 }
 
 // Lrem is the implementation of redis lrem command.
-func (s *Redis) Lrem(key string, count int, value string) (val int, err error) {
+func (s *Redis) Lrem(key string, count int, value string) (int, error) {
+	return s.LremCtx(context.Background(), key, count, value)
+}
+
+// LremCtx is the implementation of redis lrem command.
+func (s *Redis) LremCtx(ctx context.Context, key string, count int, value string) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.LRem(key, int64(count), value).Result()
+		v, err := conn.LRem(ctx, key, int64(count), value).Result()
 		if err != nil {
 			return err
 		}
@@ -882,25 +1118,35 @@ func (s *Redis) Lrem(key string, count int, value string) (val int, err error) {
 
 // Ltrim is the implementation of redis ltrim command.
 func (s *Redis) Ltrim(key string, start, stop int64) error {
+	return s.LtrimCtx(context.Background(), key, start, stop)
+}
+
+// LtrimCtx is the implementation of redis ltrim command.
+func (s *Redis) LtrimCtx(ctx context.Context, key string, start, stop int64) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		return conn.LTrim(key, start, stop).Err()
+		return conn.LTrim(ctx, key, start, stop).Err()
 	}, acceptable)
 }
 
 // Mget is the implementation of redis mget command.
-func (s *Redis) Mget(keys ...string) (val []string, err error) {
+func (s *Redis) Mget(keys ...string) ([]string, error) {
+	return s.MgetCtx(context.Background(), keys...)
+}
+
+// MgetCtx is the implementation of redis mget command.
+func (s *Redis) MgetCtx(ctx context.Context, keys ...string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.MGet(keys...).Result()
+		v, err := conn.MGet(ctx, keys...).Result()
 		if err != nil {
 			return err
 		}
@@ -913,14 +1159,19 @@ func (s *Redis) Mget(keys ...string) (val []string, err error) {
 }
 
 // Persist is the implementation of redis persist command.
-func (s *Redis) Persist(key string) (val bool, err error) {
+func (s *Redis) Persist(key string) (bool, error) {
+	return s.PersistCtx(context.Background(), key)
+}
+
+// PersistCtx is the implementation of redis persist command.
+func (s *Redis) PersistCtx(ctx context.Context, key string) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.Persist(key).Result()
+		val, err = conn.Persist(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -928,14 +1179,19 @@ func (s *Redis) Persist(key string) (val bool, err error) {
 }
 
 // Pfadd is the implementation of redis pfadd command.
-func (s *Redis) Pfadd(key string, values ...interface{}) (val bool, err error) {
+func (s *Redis) Pfadd(key string, values ...interface{}) (bool, error) {
+	return s.PfaddCtx(context.Background(), key, values...)
+}
+
+// PfaddCtx is the implementation of redis pfadd command.
+func (s *Redis) PfaddCtx(ctx context.Context, key string, values ...interface{}) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.PFAdd(key, values...).Result()
+		v, err := conn.PFAdd(ctx, key, values...).Result()
 		if err != nil {
 			return err
 		}
@@ -948,14 +1204,19 @@ func (s *Redis) Pfadd(key string, values ...interface{}) (val bool, err error) {
 }
 
 // Pfcount is the implementation of redis pfcount command.
-func (s *Redis) Pfcount(key string) (val int64, err error) {
+func (s *Redis) Pfcount(key string) (int64, error) {
+	return s.PfcountCtx(context.Background(), key)
+}
+
+// PfcountCtx is the implementation of redis pfcount command.
+func (s *Redis) PfcountCtx(ctx context.Context, key string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.PFCount(key).Result()
+		val, err = conn.PFCount(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -964,19 +1225,29 @@ func (s *Redis) Pfcount(key string) (val int64, err error) {
 
 // Pfmerge is the implementation of redis pfmerge command.
 func (s *Redis) Pfmerge(dest string, keys ...string) error {
+	return s.PfmergeCtx(context.Background(), dest, keys...)
+}
+
+// PfmergeCtx is the implementation of redis pfmerge command.
+func (s *Redis) PfmergeCtx(ctx context.Context, dest string, keys ...string) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		_, err = conn.PFMerge(dest, keys...).Result()
+		_, err = conn.PFMerge(ctx, dest, keys...).Result()
 		return err
 	}, acceptable)
 }
 
 // Ping is the implementation of redis ping command.
-func (s *Redis) Ping() (val bool) {
+func (s *Redis) Ping() bool {
+	return s.PingCtx(context.Background())
+}
+
+// PingCtx is the implementation of redis ping command.
+func (s *Redis) PingCtx(ctx context.Context) (val bool) {
 	// ignore error, error means false
 	_ = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
@@ -985,7 +1256,7 @@ func (s *Redis) Ping() (val bool) {
 			return nil
 		}
 
-		v, err := conn.Ping().Result()
+		v, err := conn.Ping(ctx).Result()
 		if err != nil {
 			val = false
 			return nil
@@ -998,15 +1269,20 @@ func (s *Redis) Ping() (val bool) {
 	return
 }
 
-// Pipelined lets fn to execute pipelined commands.
-func (s *Redis) Pipelined(fn func(Pipeliner) error) (err error) {
+// Pipelined lets fn execute pipelined commands.
+func (s *Redis) Pipelined(fn func(Pipeliner) error) error {
+	return s.PipelinedCtx(context.Background(), fn)
+}
+
+// PipelinedCtx lets fn execute pipelined commands.
+func (s *Redis) PipelinedCtx(ctx context.Context, fn func(Pipeliner) error) (err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		_, err = conn.Pipelined(fn)
+		_, err = conn.Pipelined(ctx, fn)
 		return err
 	}, acceptable)
 
@@ -1014,14 +1290,19 @@ func (s *Redis) Pipelined(fn func(Pipeliner) error) (err error) {
 }
 
 // Rpop is the implementation of redis rpop command.
-func (s *Redis) Rpop(key string) (val string, err error) {
+func (s *Redis) Rpop(key string) (string, error) {
+	return s.RpopCtx(context.Background(), key)
+}
+
+// RpopCtx is the implementation of redis rpop command.
+func (s *Redis) RpopCtx(ctx context.Context, key string) (val string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.RPop(key).Result()
+		val, err = conn.RPop(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -1029,14 +1310,19 @@ func (s *Redis) Rpop(key string) (val string, err error) {
 }
 
 // Rpush is the implementation of redis rpush command.
-func (s *Redis) Rpush(key string, values ...interface{}) (val int, err error) {
+func (s *Redis) Rpush(key string, values ...interface{}) (int, error) {
+	return s.RpushCtx(context.Background(), key, values...)
+}
+
+// RpushCtx is the implementation of redis rpush command.
+func (s *Redis) RpushCtx(ctx context.Context, key string, values ...interface{}) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.RPush(key, values...).Result()
+		v, err := conn.RPush(ctx, key, values...).Result()
 		if err != nil {
 			return err
 		}
@@ -1049,14 +1335,19 @@ func (s *Redis) Rpush(key string, values ...interface{}) (val int, err error) {
 }
 
 // Sadd is the implementation of redis sadd command.
-func (s *Redis) Sadd(key string, values ...interface{}) (val int, err error) {
+func (s *Redis) Sadd(key string, values ...interface{}) (int, error) {
+	return s.SaddCtx(context.Background(), key, values...)
+}
+
+// SaddCtx is the implementation of redis sadd command.
+func (s *Redis) SaddCtx(ctx context.Context, key string, values ...interface{}) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.SAdd(key, values...).Result()
+		v, err := conn.SAdd(ctx, key, values...).Result()
 		if err != nil {
 			return err
 		}
@@ -1070,13 +1361,19 @@ func (s *Redis) Sadd(key string, values ...interface{}) (val int, err error) {
 
 // Scan is the implementation of redis scan command.
 func (s *Redis) Scan(cursor uint64, match string, count int64) (keys []string, cur uint64, err error) {
+	return s.ScanCtx(context.Background(), cursor, match, count)
+}
+
+// ScanCtx is the implementation of redis scan command.
+func (s *Redis) ScanCtx(ctx context.Context, cursor uint64, match string, count int64) (
+	keys []string, cur uint64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		keys, cur, err = conn.Scan(cursor, match, count).Result()
+		keys, cur, err = conn.Scan(ctx, cursor, match, count).Result()
 		return err
 	}, acceptable)
 
@@ -1085,26 +1382,38 @@ func (s *Redis) Scan(cursor uint64, match string, count int64) (keys []string, c
 
 // SetBit is the implementation of redis setbit command.
 func (s *Redis) SetBit(key string, offset int64, value int) error {
+	return s.SetBitCtx(context.Background(), key, offset, value)
+}
+
+// SetBitCtx is the implementation of redis setbit command.
+func (s *Redis) SetBitCtx(ctx context.Context, key string, offset int64, value int) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		_, err = conn.SetBit(key, offset, value).Result()
+		_, err = conn.SetBit(ctx, key, offset, value).Result()
 		return err
 	}, acceptable)
 }
 
 // Sscan is the implementation of redis sscan command.
-func (s *Redis) Sscan(key string, cursor uint64, match string, count int64) (keys []string, cur uint64, err error) {
+func (s *Redis) Sscan(key string, cursor uint64, match string, count int64) (
+	keys []string, cur uint64, err error) {
+	return s.SscanCtx(context.Background(), key, cursor, match, count)
+}
+
+// SscanCtx is the implementation of redis sscan command.
+func (s *Redis) SscanCtx(ctx context.Context, key string, cursor uint64, match string, count int64) (
+	keys []string, cur uint64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		keys, cur, err = conn.SScan(key, cursor, match, count).Result()
+		keys, cur, err = conn.SScan(ctx, key, cursor, match, count).Result()
 		return err
 	}, acceptable)
 
@@ -1112,14 +1421,19 @@ func (s *Redis) Sscan(key string, cursor uint64, match string, count int64) (key
 }
 
 // Scard is the implementation of redis scard command.
-func (s *Redis) Scard(key string) (val int64, err error) {
+func (s *Redis) Scard(key string) (int64, error) {
+	return s.ScardCtx(context.Background(), key)
+}
+
+// ScardCtx is the implementation of redis scard command.
+func (s *Redis) ScardCtx(ctx context.Context, key string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SCard(key).Result()
+		val, err = conn.SCard(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -1128,47 +1442,67 @@ func (s *Redis) Scard(key string) (val int64, err error) {
 
 // ScriptLoad is the implementation of redis script load command.
 func (s *Redis) ScriptLoad(script string) (string, error) {
+	return s.ScriptLoadCtx(context.Background(), script)
+}
+
+// ScriptLoadCtx is the implementation of redis script load command.
+func (s *Redis) ScriptLoadCtx(ctx context.Context, script string) (string, error) {
 	conn, err := getRedis(s)
 	if err != nil {
 		return "", err
 	}
 
-	return conn.ScriptLoad(script).Result()
+	return conn.ScriptLoad(ctx, script).Result()
 }
 
 // Set is the implementation of redis set command.
 func (s *Redis) Set(key, value string) error {
+	return s.SetCtx(context.Background(), key, value)
+}
+
+// SetCtx is the implementation of redis set command.
+func (s *Redis) SetCtx(ctx context.Context, key, value string) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		return conn.Set(key, value, 0).Err()
+		return conn.Set(ctx, key, value, 0).Err()
 	}, acceptable)
 }
 
 // Setex is the implementation of redis setex command.
 func (s *Redis) Setex(key, value string, seconds int) error {
+	return s.SetexCtx(context.Background(), key, value, seconds)
+}
+
+// SetexCtx is the implementation of redis setex command.
+func (s *Redis) SetexCtx(ctx context.Context, key, value string, seconds int) error {
 	return s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		return conn.Set(key, value, time.Duration(seconds)*time.Second).Err()
+		return conn.Set(ctx, key, value, time.Duration(seconds)*time.Second).Err()
 	}, acceptable)
 }
 
 // Setnx is the implementation of redis setnx command.
-func (s *Redis) Setnx(key, value string) (val bool, err error) {
+func (s *Redis) Setnx(key, value string) (bool, error) {
+	return s.SetnxCtx(context.Background(), key, value)
+}
+
+// SetnxCtx is the implementation of redis setnx command.
+func (s *Redis) SetnxCtx(ctx context.Context, key, value string) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SetNX(key, value, 0).Result()
+		val, err = conn.SetNX(ctx, key, value, 0).Result()
 		return err
 	}, acceptable)
 
@@ -1176,14 +1510,19 @@ func (s *Redis) Setnx(key, value string) (val bool, err error) {
 }
 
 // SetnxEx is the implementation of redis setnx command with expire.
-func (s *Redis) SetnxEx(key, value string, seconds int) (val bool, err error) {
+func (s *Redis) SetnxEx(key, value string, seconds int) (bool, error) {
+	return s.SetnxExCtx(context.Background(), key, value, seconds)
+}
+
+// SetnxExCtx is the implementation of redis setnx command with expire.
+func (s *Redis) SetnxExCtx(ctx context.Context, key, value string, seconds int) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SetNX(key, value, time.Duration(seconds)*time.Second).Result()
+		val, err = conn.SetNX(ctx, key, value, time.Duration(seconds)*time.Second).Result()
 		return err
 	}, acceptable)
 
@@ -1191,14 +1530,19 @@ func (s *Redis) SetnxEx(key, value string, seconds int) (val bool, err error) {
 }
 
 // Sismember is the implementation of redis sismember command.
-func (s *Redis) Sismember(key string, value interface{}) (val bool, err error) {
+func (s *Redis) Sismember(key string, value interface{}) (bool, error) {
+	return s.SismemberCtx(context.Background(), key, value)
+}
+
+// SismemberCtx is the implementation of redis sismember command.
+func (s *Redis) SismemberCtx(ctx context.Context, key string, value interface{}) (val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SIsMember(key, value).Result()
+		val, err = conn.SIsMember(ctx, key, value).Result()
 		return err
 	}, acceptable)
 
@@ -1206,14 +1550,19 @@ func (s *Redis) Sismember(key string, value interface{}) (val bool, err error) {
 }
 
 // Smembers is the implementation of redis smembers command.
-func (s *Redis) Smembers(key string) (val []string, err error) {
+func (s *Redis) Smembers(key string) ([]string, error) {
+	return s.SmembersCtx(context.Background(), key)
+}
+
+// SmembersCtx is the implementation of redis smembers command.
+func (s *Redis) SmembersCtx(ctx context.Context, key string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SMembers(key).Result()
+		val, err = conn.SMembers(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -1221,14 +1570,19 @@ func (s *Redis) Smembers(key string) (val []string, err error) {
 }
 
 // Spop is the implementation of redis spop command.
-func (s *Redis) Spop(key string) (val string, err error) {
+func (s *Redis) Spop(key string) (string, error) {
+	return s.SpopCtx(context.Background(), key)
+}
+
+// SpopCtx is the implementation of redis spop command.
+func (s *Redis) SpopCtx(ctx context.Context, key string) (val string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SPop(key).Result()
+		val, err = conn.SPop(ctx, key).Result()
 		return err
 	}, acceptable)
 
@@ -1236,14 +1590,19 @@ func (s *Redis) Spop(key string) (val string, err error) {
 }
 
 // Srandmember is the implementation of redis srandmember command.
-func (s *Redis) Srandmember(key string, count int) (val []string, err error) {
+func (s *Redis) Srandmember(key string, count int) ([]string, error) {
+	return s.SrandmemberCtx(context.Background(), key, count)
+}
+
+// SrandmemberCtx is the implementation of redis srandmember command.
+func (s *Redis) SrandmemberCtx(ctx context.Context, key string, count int) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SRandMemberN(key, int64(count)).Result()
+		val, err = conn.SRandMemberN(ctx, key, int64(count)).Result()
 		return err
 	}, acceptable)
 
@@ -1251,14 +1610,19 @@ func (s *Redis) Srandmember(key string, count int) (val []string, err error) {
 }
 
 // Srem is the implementation of redis srem command.
-func (s *Redis) Srem(key string, values ...interface{}) (val int, err error) {
+func (s *Redis) Srem(key string, values ...interface{}) (int, error) {
+	return s.SremCtx(context.Background(), key, values...)
+}
+
+// SremCtx is the implementation of redis srem command.
+func (s *Redis) SremCtx(ctx context.Context, key string, values ...interface{}) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.SRem(key, values...).Result()
+		v, err := conn.SRem(ctx, key, values...).Result()
 		if err != nil {
 			return err
 		}
@@ -1276,14 +1640,19 @@ func (s *Redis) String() string {
 }
 
 // Sunion is the implementation of redis sunion command.
-func (s *Redis) Sunion(keys ...string) (val []string, err error) {
+func (s *Redis) Sunion(keys ...string) ([]string, error) {
+	return s.SunionCtx(context.Background(), keys...)
+}
+
+// SunionCtx is the implementation of redis sunion command.
+func (s *Redis) SunionCtx(ctx context.Context, keys ...string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SUnion(keys...).Result()
+		val, err = conn.SUnion(ctx, keys...).Result()
 		return err
 	}, acceptable)
 
@@ -1291,14 +1660,20 @@ func (s *Redis) Sunion(keys ...string) (val []string, err error) {
 }
 
 // Sunionstore is the implementation of redis sunionstore command.
-func (s *Redis) Sunionstore(destination string, keys ...string) (val int, err error) {
+func (s *Redis) Sunionstore(destination string, keys ...string) (int, error) {
+	return s.SunionstoreCtx(context.Background(), destination, keys...)
+}
+
+// SunionstoreCtx is the implementation of redis sunionstore command.
+func (s *Redis) SunionstoreCtx(ctx context.Context, destination string, keys ...string) (
+	val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.SUnionStore(destination, keys...).Result()
+		v, err := conn.SUnionStore(ctx, destination, keys...).Result()
 		if err != nil {
 			return err
 		}
@@ -1311,14 +1686,19 @@ func (s *Redis) Sunionstore(destination string, keys ...string) (val int, err er
 }
 
 // Sdiff is the implementation of redis sdiff command.
-func (s *Redis) Sdiff(keys ...string) (val []string, err error) {
+func (s *Redis) Sdiff(keys ...string) ([]string, error) {
+	return s.SdiffCtx(context.Background(), keys...)
+}
+
+// SdiffCtx is the implementation of redis sdiff command.
+func (s *Redis) SdiffCtx(ctx context.Context, keys ...string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SDiff(keys...).Result()
+		val, err = conn.SDiff(ctx, keys...).Result()
 		return err
 	}, acceptable)
 
@@ -1326,14 +1706,20 @@ func (s *Redis) Sdiff(keys ...string) (val []string, err error) {
 }
 
 // Sdiffstore is the implementation of redis sdiffstore command.
-func (s *Redis) Sdiffstore(destination string, keys ...string) (val int, err error) {
+func (s *Redis) Sdiffstore(destination string, keys ...string) (int, error) {
+	return s.SdiffstoreCtx(context.Background(), destination, keys...)
+}
+
+// SdiffstoreCtx is the implementation of redis sdiffstore command.
+func (s *Redis) SdiffstoreCtx(ctx context.Context, destination string, keys ...string) (
+	val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.SDiffStore(destination, keys...).Result()
+		v, err := conn.SDiffStore(ctx, destination, keys...).Result()
 		if err != nil {
 			return err
 		}
@@ -1346,14 +1732,19 @@ func (s *Redis) Sdiffstore(destination string, keys ...string) (val int, err err
 }
 
 // Sinter is the implementation of redis sinter command.
-func (s *Redis) Sinter(keys ...string) (val []string, err error) {
+func (s *Redis) Sinter(keys ...string) ([]string, error) {
+	return s.SinterCtx(context.Background(), keys...)
+}
+
+// SinterCtx is the implementation of redis sinter command.
+func (s *Redis) SinterCtx(ctx context.Context, keys ...string) (val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.SInter(keys...).Result()
+		val, err = conn.SInter(ctx, keys...).Result()
 		return err
 	}, acceptable)
 
@@ -1361,14 +1752,20 @@ func (s *Redis) Sinter(keys ...string) (val []string, err error) {
 }
 
 // Sinterstore is the implementation of redis sinterstore command.
-func (s *Redis) Sinterstore(destination string, keys ...string) (val int, err error) {
+func (s *Redis) Sinterstore(destination string, keys ...string) (int, error) {
+	return s.SinterstoreCtx(context.Background(), destination, keys...)
+}
+
+// SinterstoreCtx is the implementation of redis sinterstore command.
+func (s *Redis) SinterstoreCtx(ctx context.Context, destination string, keys ...string) (
+	val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.SInterStore(destination, keys...).Result()
+		v, err := conn.SInterStore(ctx, destination, keys...).Result()
 		if err != nil {
 			return err
 		}
@@ -1381,14 +1778,19 @@ func (s *Redis) Sinterstore(destination string, keys ...string) (val int, err er
 }
 
 // Ttl is the implementation of redis ttl command.
-func (s *Redis) Ttl(key string) (val int, err error) {
+func (s *Redis) Ttl(key string) (int, error) {
+	return s.TtlCtx(context.Background(), key)
+}
+
+// TtlCtx is the implementation of redis ttl command.
+func (s *Redis) TtlCtx(ctx context.Context, key string) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		duration, err := conn.TTL(key).Result()
+		duration, err := conn.TTL(ctx, key).Result()
 		if err != nil {
 			return err
 		}
@@ -1401,14 +1803,20 @@ func (s *Redis) Ttl(key string) (val int, err error) {
 }
 
 // Zadd is the implementation of redis zadd command.
-func (s *Redis) Zadd(key string, score int64, value string) (val bool, err error) {
+func (s *Redis) Zadd(key string, score int64, value string) (bool, error) {
+	return s.ZaddCtx(context.Background(), key, score, value)
+}
+
+// ZaddCtx is the implementation of redis zadd command.
+func (s *Redis) ZaddCtx(ctx context.Context, key string, score int64, value string) (
+	val bool, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZAdd(key, red.Z{
+		v, err := conn.ZAdd(ctx, key, &red.Z{
 			Score:  float64(score),
 			Member: value,
 		}).Result()
@@ -1424,20 +1832,25 @@ func (s *Redis) Zadd(key string, score int64, value string) (val bool, err error
 }
 
 // Zadds is the implementation of redis zadds command.
-func (s *Redis) Zadds(key string, ps ...Pair) (val int64, err error) {
+func (s *Redis) Zadds(key string, ps ...Pair) (int64, error) {
+	return s.ZaddsCtx(context.Background(), key, ps...)
+}
+
+// ZaddsCtx is the implementation of redis zadds command.
+func (s *Redis) ZaddsCtx(ctx context.Context, key string, ps ...Pair) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		var zs []red.Z
+		var zs []*red.Z
 		for _, p := range ps {
-			z := red.Z{Score: float64(p.Score), Member: p.Key}
+			z := &red.Z{Score: float64(p.Score), Member: p.Key}
 			zs = append(zs, z)
 		}
 
-		v, err := conn.ZAdd(key, zs...).Result()
+		v, err := conn.ZAdd(ctx, key, zs...).Result()
 		if err != nil {
 			return err
 		}
@@ -1450,14 +1863,19 @@ func (s *Redis) Zadds(key string, ps ...Pair) (val int64, err error) {
 }
 
 // Zcard is the implementation of redis zcard command.
-func (s *Redis) Zcard(key string) (val int, err error) {
+func (s *Redis) Zcard(key string) (int, error) {
+	return s.ZcardCtx(context.Background(), key)
+}
+
+// ZcardCtx is the implementation of redis zcard command.
+func (s *Redis) ZcardCtx(ctx context.Context, key string) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZCard(key).Result()
+		v, err := conn.ZCard(ctx, key).Result()
 		if err != nil {
 			return err
 		}
@@ -1470,14 +1888,20 @@ func (s *Redis) Zcard(key string) (val int, err error) {
 }
 
 // Zcount is the implementation of redis zcount command.
-func (s *Redis) Zcount(key string, start, stop int64) (val int, err error) {
+func (s *Redis) Zcount(key string, start, stop int64) (int, error) {
+	return s.ZcountCtx(context.Background(), key, start, stop)
+}
+
+// ZcountCtx is the implementation of redis zcount command.
+func (s *Redis) ZcountCtx(ctx context.Context, key string, start, stop int64) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZCount(key, strconv.FormatInt(start, 10), strconv.FormatInt(stop, 10)).Result()
+		v, err := conn.ZCount(ctx, key, strconv.FormatInt(start, 10),
+			strconv.FormatInt(stop, 10)).Result()
 		if err != nil {
 			return err
 		}
@@ -1490,14 +1914,20 @@ func (s *Redis) Zcount(key string, start, stop int64) (val int, err error) {
 }
 
 // Zincrby is the implementation of redis zincrby command.
-func (s *Redis) Zincrby(key string, increment int64, field string) (val int64, err error) {
+func (s *Redis) Zincrby(key string, increment int64, field string) (int64, error) {
+	return s.ZincrbyCtx(context.Background(), key, increment, field)
+}
+
+// ZincrbyCtx is the implementation of redis zincrby command.
+func (s *Redis) ZincrbyCtx(ctx context.Context, key string, increment int64, field string) (
+	val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZIncrBy(key, float64(increment), field).Result()
+		v, err := conn.ZIncrBy(ctx, key, float64(increment), field).Result()
 		if err != nil {
 			return err
 		}
@@ -1510,14 +1940,19 @@ func (s *Redis) Zincrby(key string, increment int64, field string) (val int64, e
 }
 
 // Zscore is the implementation of redis zscore command.
-func (s *Redis) Zscore(key, value string) (val int64, err error) {
+func (s *Redis) Zscore(key, value string) (int64, error) {
+	return s.ZscoreCtx(context.Background(), key, value)
+}
+
+// ZscoreCtx is the implementation of redis zscore command.
+func (s *Redis) ZscoreCtx(ctx context.Context, key, value string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZScore(key, value).Result()
+		v, err := conn.ZScore(ctx, key, value).Result()
 		if err != nil {
 			return err
 		}
@@ -1530,14 +1965,19 @@ func (s *Redis) Zscore(key, value string) (val int64, err error) {
 }
 
 // Zrank is the implementation of redis zrank command.
-func (s *Redis) Zrank(key, field string) (val int64, err error) {
+func (s *Redis) Zrank(key, field string) (int64, error) {
+	return s.ZrankCtx(context.Background(), key, field)
+}
+
+// ZrankCtx is the implementation of redis zrank command.
+func (s *Redis) ZrankCtx(ctx context.Context, key, field string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.ZRank(key, field).Result()
+		val, err = conn.ZRank(ctx, key, field).Result()
 		return err
 	}, acceptable)
 
@@ -1545,14 +1985,19 @@ func (s *Redis) Zrank(key, field string) (val int64, err error) {
 }
 
 // Zrem is the implementation of redis zrem command.
-func (s *Redis) Zrem(key string, values ...interface{}) (val int, err error) {
+func (s *Redis) Zrem(key string, values ...interface{}) (int, error) {
+	return s.ZremCtx(context.Background(), key, values...)
+}
+
+// ZremCtx is the implementation of redis zrem command.
+func (s *Redis) ZremCtx(ctx context.Context, key string, values ...interface{}) (val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRem(key, values...).Result()
+		v, err := conn.ZRem(ctx, key, values...).Result()
 		if err != nil {
 			return err
 		}
@@ -1565,14 +2010,20 @@ func (s *Redis) Zrem(key string, values ...interface{}) (val int, err error) {
 }
 
 // Zremrangebyscore is the implementation of redis zremrangebyscore command.
-func (s *Redis) Zremrangebyscore(key string, start, stop int64) (val int, err error) {
+func (s *Redis) Zremrangebyscore(key string, start, stop int64) (int, error) {
+	return s.ZremrangebyscoreCtx(context.Background(), key, start, stop)
+}
+
+// ZremrangebyscoreCtx is the implementation of redis zremrangebyscore command.
+func (s *Redis) ZremrangebyscoreCtx(ctx context.Context, key string, start, stop int64) (
+	val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRemRangeByScore(key, strconv.FormatInt(start, 10),
+		v, err := conn.ZRemRangeByScore(ctx, key, strconv.FormatInt(start, 10),
 			strconv.FormatInt(stop, 10)).Result()
 		if err != nil {
 			return err
@@ -1586,14 +2037,20 @@ func (s *Redis) Zremrangebyscore(key string, start, stop int64) (val int, err er
 }
 
 // Zremrangebyrank is the implementation of redis zremrangebyrank command.
-func (s *Redis) Zremrangebyrank(key string, start, stop int64) (val int, err error) {
+func (s *Redis) Zremrangebyrank(key string, start, stop int64) (int, error) {
+	return s.ZremrangebyrankCtx(context.Background(), key, start, stop)
+}
+
+// ZremrangebyrankCtx is the implementation of redis zremrangebyrank command.
+func (s *Redis) ZremrangebyrankCtx(ctx context.Context, key string, start, stop int64) (
+	val int, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRemRangeByRank(key, start, stop).Result()
+		v, err := conn.ZRemRangeByRank(ctx, key, start, stop).Result()
 		if err != nil {
 			return err
 		}
@@ -1606,14 +2063,20 @@ func (s *Redis) Zremrangebyrank(key string, start, stop int64) (val int, err err
 }
 
 // Zrange is the implementation of redis zrange command.
-func (s *Redis) Zrange(key string, start, stop int64) (val []string, err error) {
+func (s *Redis) Zrange(key string, start, stop int64) ([]string, error) {
+	return s.ZrangeCtx(context.Background(), key, start, stop)
+}
+
+// ZrangeCtx is the implementation of redis zrange command.
+func (s *Redis) ZrangeCtx(ctx context.Context, key string, start, stop int64) (
+	val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.ZRange(key, start, stop).Result()
+		val, err = conn.ZRange(ctx, key, start, stop).Result()
 		return err
 	}, acceptable)
 
@@ -1621,14 +2084,20 @@ func (s *Redis) Zrange(key string, start, stop int64) (val []string, err error)
 }
 
 // ZrangeWithScores is the implementation of redis zrange command with scores.
-func (s *Redis) ZrangeWithScores(key string, start, stop int64) (val []Pair, err error) {
+func (s *Redis) ZrangeWithScores(key string, start, stop int64) ([]Pair, error) {
+	return s.ZrangeWithScoresCtx(context.Background(), key, start, stop)
+}
+
+// ZrangeWithScoresCtx is the implementation of redis zrange command with scores.
+func (s *Redis) ZrangeWithScoresCtx(ctx context.Context, key string, start, stop int64) (
+	val []Pair, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRangeWithScores(key, start, stop).Result()
+		v, err := conn.ZRangeWithScores(ctx, key, start, stop).Result()
 		if err != nil {
 			return err
 		}
@@ -1641,14 +2110,20 @@ func (s *Redis) ZrangeWithScores(key string, start, stop int64) (val []Pair, err
 }
 
 // ZRevRangeWithScores is the implementation of redis zrevrange command with scores.
-func (s *Redis) ZRevRangeWithScores(key string, start, stop int64) (val []Pair, err error) {
+func (s *Redis) ZRevRangeWithScores(key string, start, stop int64) ([]Pair, error) {
+	return s.ZRevRangeWithScoresCtx(context.Background(), key, start, stop)
+}
+
+// ZRevRangeWithScoresCtx is the implementation of redis zrevrange command with scores.
+func (s *Redis) ZRevRangeWithScoresCtx(ctx context.Context, key string, start, stop int64) (
+	val []Pair, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRevRangeWithScores(key, start, stop).Result()
+		v, err := conn.ZRevRangeWithScores(ctx, key, start, stop).Result()
 		if err != nil {
 			return err
 		}
@@ -1661,14 +2136,20 @@ func (s *Redis) ZRevRangeWithScores(key string, start, stop int64) (val []Pair,
 }
 
 // ZrangebyscoreWithScores is the implementation of redis zrangebyscore command with scores.
-func (s *Redis) ZrangebyscoreWithScores(key string, start, stop int64) (val []Pair, err error) {
+func (s *Redis) ZrangebyscoreWithScores(key string, start, stop int64) ([]Pair, error) {
+	return s.ZrangebyscoreWithScoresCtx(context.Background(), key, start, stop)
+}
+
+// ZrangebyscoreWithScoresCtx is the implementation of redis zrangebyscore command with scores.
+func (s *Redis) ZrangebyscoreWithScoresCtx(ctx context.Context, key string, start, stop int64) (
+	val []Pair, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRangeByScoreWithScores(key, red.ZRangeBy{
+		v, err := conn.ZRangeByScoreWithScores(ctx, key, &red.ZRangeBy{
 			Min: strconv.FormatInt(start, 10),
 			Max: strconv.FormatInt(stop, 10),
 		}).Result()
@@ -1683,9 +2164,17 @@ func (s *Redis) ZrangebyscoreWithScores(key string, start, stop int64) (val []Pa
 	return
 }
 
-// ZrangebyscoreWithScoresAndLimit is the implementation of redis zrangebyscore command with scores and limit.
-func (s *Redis) ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) (
-	val []Pair, err error) {
+// ZrangebyscoreWithScoresAndLimit is the implementation of redis zrangebyscore command
+// with scores and limit.
+func (s *Redis) ZrangebyscoreWithScoresAndLimit(key string, start, stop int64,
+	page, size int) ([]Pair, error) {
+	return s.ZrangebyscoreWithScoresAndLimitCtx(context.Background(), key, start, stop, page, size)
+}
+
+// ZrangebyscoreWithScoresAndLimitCtx is the implementation of redis zrangebyscore command
+// with scores and limit.
+func (s *Redis) ZrangebyscoreWithScoresAndLimitCtx(ctx context.Context, key string, start,
+	stop int64, page, size int) (val []Pair, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		if size <= 0 {
 			return nil
@@ -1696,7 +2185,7 @@ func (s *Redis) ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, p
 			return err
 		}
 
-		v, err := conn.ZRangeByScoreWithScores(key, red.ZRangeBy{
+		v, err := conn.ZRangeByScoreWithScores(ctx, key, &red.ZRangeBy{
 			Min:    strconv.FormatInt(start, 10),
 			Max:    strconv.FormatInt(stop, 10),
 			Offset: int64(page * size),
@@ -1714,14 +2203,20 @@ func (s *Redis) ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, p
 }
 
 // Zrevrange is the implementation of redis zrevrange command.
-func (s *Redis) Zrevrange(key string, start, stop int64) (val []string, err error) {
+func (s *Redis) Zrevrange(key string, start, stop int64) ([]string, error) {
+	return s.ZrevrangeCtx(context.Background(), key, start, stop)
+}
+
+// ZrevrangeCtx is the implementation of redis zrevrange command.
+func (s *Redis) ZrevrangeCtx(ctx context.Context, key string, start, stop int64) (
+	val []string, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.ZRevRange(key, start, stop).Result()
+		val, err = conn.ZRevRange(ctx, key, start, stop).Result()
 		return err
 	}, acceptable)
 
@@ -1729,14 +2224,20 @@ func (s *Redis) Zrevrange(key string, start, stop int64) (val []string, err erro
 }
 
 // ZrevrangebyscoreWithScores is the implementation of redis zrevrangebyscore command with scores.
-func (s *Redis) ZrevrangebyscoreWithScores(key string, start, stop int64) (val []Pair, err error) {
+func (s *Redis) ZrevrangebyscoreWithScores(key string, start, stop int64) ([]Pair, error) {
+	return s.ZrevrangebyscoreWithScoresCtx(context.Background(), key, start, stop)
+}
+
+// ZrevrangebyscoreWithScoresCtx is the implementation of redis zrevrangebyscore command with scores.
+func (s *Redis) ZrevrangebyscoreWithScoresCtx(ctx context.Context, key string, start, stop int64) (
+	val []Pair, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		v, err := conn.ZRevRangeByScoreWithScores(key, red.ZRangeBy{
+		v, err := conn.ZRevRangeByScoreWithScores(ctx, key, &red.ZRangeBy{
 			Min: strconv.FormatInt(start, 10),
 			Max: strconv.FormatInt(stop, 10),
 		}).Result()
@@ -1751,9 +2252,17 @@ func (s *Redis) ZrevrangebyscoreWithScores(key string, start, stop int64) (val [
 	return
 }
 
-// ZrevrangebyscoreWithScoresAndLimit is the implementation of redis zrevrangebyscore command with scores and limit.
-func (s *Redis) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) (
-	val []Pair, err error) {
+// ZrevrangebyscoreWithScoresAndLimit is the implementation of redis zrevrangebyscore command
+// with scores and limit.
+func (s *Redis) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64,
+	page, size int) ([]Pair, error) {
+	return s.ZrevrangebyscoreWithScoresAndLimitCtx(context.Background(), key, start, stop, page, size)
+}
+
+// ZrevrangebyscoreWithScoresAndLimitCtx is the implementation of redis zrevrangebyscore command
+// with scores and limit.
+func (s *Redis) ZrevrangebyscoreWithScoresAndLimitCtx(ctx context.Context, key string,
+	start, stop int64, page, size int) (val []Pair, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		if size <= 0 {
 			return nil
@@ -1764,7 +2273,7 @@ func (s *Redis) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64
 			return err
 		}
 
-		v, err := conn.ZRevRangeByScoreWithScores(key, red.ZRangeBy{
+		v, err := conn.ZRevRangeByScoreWithScores(ctx, key, &red.ZRangeBy{
 			Min:    strconv.FormatInt(start, 10),
 			Max:    strconv.FormatInt(stop, 10),
 			Offset: int64(page * size),
@@ -1782,14 +2291,19 @@ func (s *Redis) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64
 }
 
 // Zrevrank is the implementation of redis zrevrank command.
-func (s *Redis) Zrevrank(key, field string) (val int64, err error) {
+func (s *Redis) Zrevrank(key, field string) (int64, error) {
+	return s.ZrevrankCtx(context.Background(), key, field)
+}
+
+// ZrevrankCtx is the implementation of redis zrevrank command.
+func (s *Redis) ZrevrankCtx(ctx context.Context, key, field string) (val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.ZRevRank(key, field).Result()
+		val, err = conn.ZRevRank(ctx, key, field).Result()
 		return err
 	}, acceptable)
 
@@ -1797,14 +2311,20 @@ func (s *Redis) Zrevrank(key, field string) (val int64, err error) {
 }
 
 // Zunionstore is the implementation of redis zunionstore command.
-func (s *Redis) Zunionstore(dest string, store ZStore, keys ...string) (val int64, err error) {
+func (s *Redis) Zunionstore(dest string, store *ZStore) (int64, error) {
+	return s.ZunionstoreCtx(context.Background(), dest, store)
+}
+
+// ZunionstoreCtx is the implementation of redis zunionstore command.
+func (s *Redis) ZunionstoreCtx(ctx context.Context, dest string, store *ZStore) (
+	val int64, err error) {
 	err = s.brk.DoWithAcceptable(func() error {
 		conn, err := getRedis(s)
 		if err != nil {
 			return err
 		}
 
-		val, err = conn.ZUnionStore(dest, store, keys...).Result()
+		val, err = conn.ZUnionStore(ctx, dest, store).Result()
 		return err
 	}, acceptable)
 
diff --git a/core/stores/redis/redisblockingnode.go b/core/stores/redis/redisblockingnode.go
index 4594c999..696b8860 100644
--- a/core/stores/redis/redisblockingnode.go
+++ b/core/stores/redis/redisblockingnode.go
@@ -3,7 +3,7 @@ package redis
 import (
 	"fmt"
 
-	red "github.com/go-redis/redis"
+	red "github.com/go-redis/redis/v8"
 	"github.com/zeromicro/go-zero/core/logx"
 )
 
diff --git a/core/stores/redis/redisclientmanager.go b/core/stores/redis/redisclientmanager.go
index 6ac6ac67..fa4b72c9 100644
--- a/core/stores/redis/redisclientmanager.go
+++ b/core/stores/redis/redisclientmanager.go
@@ -4,7 +4,7 @@ import (
 	"crypto/tls"
 	"io"
 
-	red "github.com/go-redis/redis"
+	red "github.com/go-redis/redis/v8"
 	"github.com/zeromicro/go-zero/core/syncx"
 )
 
@@ -32,7 +32,8 @@ func getClient(r *Redis) (*red.Client, error) {
 			MinIdleConns: idleConns,
 			TLSConfig:    tlsConfig,
 		})
-		store.WrapProcess(checkDuration)
+		store.AddHook(durationHook)
+
 		return store, nil
 	})
 	if err != nil {
diff --git a/core/stores/redis/redisclustermanager.go b/core/stores/redis/redisclustermanager.go
index 4bf7d97f..de8b1203 100644
--- a/core/stores/redis/redisclustermanager.go
+++ b/core/stores/redis/redisclustermanager.go
@@ -4,7 +4,7 @@ import (
 	"crypto/tls"
 	"io"
 
-	red "github.com/go-redis/redis"
+	red "github.com/go-redis/redis/v8"
 	"github.com/zeromicro/go-zero/core/syncx"
 )
 
@@ -25,7 +25,7 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
 			MinIdleConns: idleConns,
 			TLSConfig:    tlsConfig,
 		})
-		store.WrapProcess(checkDuration)
+		store.AddHook(durationHook)
 
 		return store, nil
 	})
diff --git a/core/stores/redis/redislock.go b/core/stores/redis/redislock.go
index 58711f03..daa9bdec 100644
--- a/core/stores/redis/redislock.go
+++ b/core/stores/redis/redislock.go
@@ -5,7 +5,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	red "github.com/go-redis/redis"
+	red "github.com/go-redis/redis/v8"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/stringx"
 )
diff --git a/core/timex/ticker.go b/core/timex/ticker.go
index 59b5eb9d..2691a030 100644
--- a/core/timex/ticker.go
+++ b/core/timex/ticker.go
@@ -7,6 +7,9 @@ import (
 	"github.com/zeromicro/go-zero/core/lang"
 )
 
+// errTimeout indicates a timeout.
+var errTimeout = errors.New("timeout")
+
 type (
 	// Ticker interface wraps the Chan and Stop methods.
 	Ticker interface {
@@ -70,7 +73,7 @@ func (ft *fakeTicker) Tick() {
 func (ft *fakeTicker) Wait(d time.Duration) error {
 	select {
 	case <-time.After(d):
-		return errors.New("timeout")
+		return errTimeout
 	case <-ft.done:
 		return nil
 	}
diff --git a/go.mod b/go.mod
index 6e1cc575..f406d4ed 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,6 @@ require (
 	github.com/DATA-DOG/go-sqlmock v1.5.0
 	github.com/alicebob/miniredis/v2 v2.17.0
 	github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
-	github.com/go-redis/redis v6.15.9+incompatible
 	github.com/go-sql-driver/mysql v1.6.0
 	github.com/golang-jwt/jwt/v4 v4.2.0
 	github.com/golang/mock v1.6.0
@@ -42,6 +41,7 @@ require (
 require (
 	github.com/fatih/color v1.10.0 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-redis/redis/v8 v8.11.4
 	github.com/mattn/go-runewidth v0.0.13 // indirect
 	github.com/openzipkin/zipkin-go v0.4.0 // indirect
 	golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
diff --git a/go.sum b/go.sum
index 822cc571..502590e1 100644
--- a/go.sum
+++ b/go.sum
@@ -62,8 +62,9 @@ github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwj
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -87,6 +88,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -142,8 +145,8 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9
 github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
 github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
-github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
+github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
diff --git a/tools/goctl/go.mod b/tools/goctl/go.mod
index 526c2a69..f43d8f30 100644
--- a/tools/goctl/go.mod
+++ b/tools/goctl/go.mod
@@ -13,5 +13,5 @@ require (
 	github.com/urfave/cli v1.22.5
 	github.com/zeromicro/antlr v0.0.1
 	github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348
-	github.com/zeromicro/go-zero v1.3.0-beta
+	github.com/zeromicro/go-zero v1.3.0
 )
diff --git a/tools/goctl/go.sum b/tools/goctl/go.sum
index 64ee1a28..a3bbc0a8 100644
--- a/tools/goctl/go.sum
+++ b/tools/goctl/go.sum
@@ -360,8 +360,8 @@ github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk
 github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
 github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 h1:OhxL9tn28gDeJVzreIUiE5oVxZCjL3tBJ0XBNw8p5R8=
 github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
-github.com/zeromicro/go-zero v1.3.0-beta h1:jNwtjGzAV6PSklpXbLCmQph7BzfH7abcUIOG9odWMsM=
-github.com/zeromicro/go-zero v1.3.0-beta/go.mod h1:Hy4o1VFAt32lXaQMbaBhoFeZjA/rJqJ4PTGNdGsURcc=
+github.com/zeromicro/go-zero v1.3.0 h1:Eyn36yBtR043sm4YKmxR6eS3UA/GtZDktQ+UqIJ3Lm0=
+github.com/zeromicro/go-zero v1.3.0/go.mod h1:Hy4o1VFAt32lXaQMbaBhoFeZjA/rJqJ4PTGNdGsURcc=
 go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
 go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
 go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=


Test patch:
diff --git a/core/limit/periodlimit_test.go b/core/limit/periodlimit_test.go
index 0b8dfa32..8fc4403c 100644
--- a/core/limit/periodlimit_test.go
+++ b/core/limit/periodlimit_test.go
@@ -23,10 +23,9 @@ func TestPeriodLimit_RedisUnavailable(t *testing.T) {
 
 	const (
 		seconds = 1
-		total   = 100
 		quota   = 5
 	)
-	l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit")
+	l := NewPeriodLimit(seconds, quota, redis.New(s.Addr()), "periodlimit")
 	s.Close()
 	val, err := l.Take("first")
 	assert.NotNil(t, err)
diff --git a/core/stores/redis/hook_test.go b/core/stores/redis/hook_test.go
new file mode 100644
index 00000000..1d3dce5f
--- /dev/null
+++ b/core/stores/redis/hook_test.go
@@ -0,0 +1,138 @@
+package redis
+
+import (
+	"context"
+	"log"
+	"strings"
+	"testing"
+	"time"
+
+	red "github.com/go-redis/redis/v8"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestHookProcessCase1(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx, err := durationHook.BeforeProcess(context.Background(), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
+	assert.False(t, strings.Contains(buf.String(), "slow"))
+}
+
+func TestHookProcessCase2(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx, err := durationHook.BeforeProcess(context.Background(), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	time.Sleep(slowThreshold.Load() + time.Millisecond)
+
+	assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background(), "foo", "bar")))
+	assert.True(t, strings.Contains(buf.String(), "slow"))
+}
+
+func TestHookProcessCase3(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	assert.Nil(t, durationHook.AfterProcess(context.Background(), red.NewCmd(context.Background())))
+	assert.True(t, buf.Len() == 0)
+}
+
+func TestHookProcessCase4(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx := context.WithValue(context.Background(), startTimeKey, "foo")
+	assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
+	assert.True(t, buf.Len() == 0)
+}
+
+func TestHookProcessPipelineCase1(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
+		red.NewCmd(context.Background()),
+	}))
+	assert.False(t, strings.Contains(buf.String(), "slow"))
+}
+
+func TestHookProcessPipelineCase2(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	time.Sleep(slowThreshold.Load() + time.Millisecond)
+
+	assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
+		red.NewCmd(context.Background(), "foo", "bar"),
+	}))
+	assert.True(t, strings.Contains(buf.String(), "slow"))
+}
+
+func TestHookProcessPipelineCase3(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	assert.Nil(t, durationHook.AfterProcessPipeline(context.Background(), []red.Cmder{
+		red.NewCmd(context.Background()),
+	}))
+	assert.True(t, buf.Len() == 0)
+}
+
+func TestHookProcessPipelineCase4(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx := context.WithValue(context.Background(), startTimeKey, "foo")
+	assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
+		red.NewCmd(context.Background()),
+	}))
+	assert.True(t, buf.Len() == 0)
+}
+
+func TestHookProcessPipelineCase5(t *testing.T) {
+	writer := log.Writer()
+	var buf strings.Builder
+	log.SetOutput(&buf)
+	defer log.SetOutput(writer)
+
+	ctx := context.WithValue(context.Background(), startTimeKey, "foo")
+	assert.Nil(t, durationHook.AfterProcessPipeline(ctx, nil))
+	assert.True(t, buf.Len() == 0)
+}
diff --git a/core/stores/redis/redis_test.go b/core/stores/redis/redis_test.go
index ee50c2e0..1c196e85 100644
--- a/core/stores/redis/redis_test.go
+++ b/core/stores/redis/redis_test.go
@@ -1,6 +1,7 @@
 package redis
 
 import (
+	"context"
 	"crypto/tls"
 	"errors"
 	"io"
@@ -9,7 +10,7 @@ import (
 	"time"
 
 	"github.com/alicebob/miniredis/v2"
-	red "github.com/go-redis/redis"
+	red "github.com/go-redis/redis/v8"
 	"github.com/stretchr/testify/assert"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/stringx"
@@ -964,13 +965,14 @@ func TestRedis_SortedSet(t *testing.T) {
 		assert.NotNil(t, err)
 		client.Zadd("second", 2, "aa")
 		client.Zadd("third", 3, "bbb")
-		val, err = client.Zunionstore("union", ZStore{
+		val, err = client.Zunionstore("union", &ZStore{
+			Keys:      []string{"second", "third"},
 			Weights:   []float64{1, 2},
 			Aggregate: "SUM",
-		}, "second", "third")
+		})
 		assert.Nil(t, err)
 		assert.Equal(t, int64(2), val)
-		_, err = New(client.Addr, badType()).Zunionstore("union", ZStore{})
+		_, err = New(client.Addr, badType()).Zunionstore("union", &ZStore{})
 		assert.NotNil(t, err)
 		vals, err = client.Zrange("union", 0, 10000)
 		assert.Nil(t, err)
@@ -988,9 +990,9 @@ func TestRedis_Pipelined(t *testing.T) {
 		}))
 		err := client.Pipelined(
 			func(pipe Pipeliner) error {
-				pipe.Incr("pipelined_counter")
-				pipe.Expire("pipelined_counter", time.Hour)
-				pipe.ZAdd("zadd", Z{Score: 12, Member: "zadd"})
+				pipe.Incr(context.Background(), "pipelined_counter")
+				pipe.Expire(context.Background(), "pipelined_counter", time.Hour)
+				pipe.ZAdd(context.Background(), "zadd", &Z{Score: 12, Member: "zadd"})
 				return nil
 			},
 		)
@@ -1187,6 +1189,6 @@ type mockedNode struct {
 	RedisNode
 }
 
-func (n mockedNode) BLPop(timeout time.Duration, keys ...string) *red.StringSliceCmd {
-	return red.NewStringSliceCmd("foo", "bar")
+func (n mockedNode) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *red.StringSliceCmd {
+	return red.NewStringSliceCmd(context.Background(), "foo", "bar")
 }
diff --git a/core/stores/redis/redistest/redistest.go b/core/stores/redis/redistest/redistest.go
index 2625e3ca..35f634af 100644
--- a/core/stores/redis/redistest/redistest.go
+++ b/core/stores/redis/redistest/redistest.go
@@ -17,10 +17,12 @@ func CreateRedis() (r *redis.Redis, clean func(), err error) {
 
 	return redis.New(mr.Addr()), func() {
 		ch := make(chan lang.PlaceholderType)
+
 		go func() {
 			mr.Close()
 			close(ch)
 		}()
+
 		select {
 		case <-ch:
 		case <-time.After(time.Second):