Repository: zeromicro/go-zero
Pull request #1187 (2021-11-01 00:08:02)

feat: slow threshold customizable in redis


Patch:
diff --git a/core/stores/redis/conf.go b/core/stores/redis/conf.go
index 776bd5ac..2d93723b 100644
--- a/core/stores/redis/conf.go
+++ b/core/stores/redis/conf.go
@@ -1,11 +1,6 @@
 package redis
 
-import (
-	"errors"
-	"time"
-
-	"github.com/tal-tech/go-zero/core/conf"
-)
+import "errors"
 
 var (
 	// ErrEmptyHost is an error that indicates no redis host is set.
@@ -19,11 +14,10 @@ var (
 type (
 	// A RedisConf is a redis config.
 	RedisConf struct {
-		Host          string
-		Type          string        `json:",default=node,options=node|cluster"`
-		Pass          string        `json:",optional"`
-		Tls           bool          `json:",default=false,options=true|false"`
-		SlowThreshold time.Duration `json:",default=100ms"`
+		Host string
+		Type string `json:",default=node,options=node|cluster"`
+		Pass string `json:",optional"`
+		Tls  bool   `json:",default=false,options=true|false"`
 	}
 
 	// A RedisKeyConf is a redis config with key.
@@ -42,9 +36,6 @@ func (rc RedisConf) NewRedis() *Redis {
 	if len(rc.Pass) > 0 {
 		opts = append(opts, WithPass(rc.Pass))
 	}
-	if rc.SlowThreshold > 0 {
-		opts = append(opts, WithSlowThreshold(conf.CheckedDuration(rc.SlowThreshold)))
-	}
 	if rc.Tls {
 		opts = append(opts, WithTLS())
 	}
diff --git a/core/stores/redis/process.go b/core/stores/redis/process.go
index 2624acbe..746fa3ab 100644
--- a/core/stores/redis/process.go
+++ b/core/stores/redis/process.go
@@ -2,7 +2,6 @@ package redis
 
 import (
 	"strings"
-	"time"
 
 	red "github.com/go-redis/redis"
 	"github.com/tal-tech/go-zero/core/logx"
@@ -10,26 +9,24 @@ import (
 	"github.com/tal-tech/go-zero/core/timex"
 )
 
-func checkDuration(slowThreshold time.Duration) func(proc func(red.Cmder) error) func(red.Cmder) error {
-	return func(proc func(red.Cmder) error) func(red.Cmder) error {
-		return func(cmd red.Cmder) error {
-			start := timex.Now()
+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 {
-					var buf strings.Builder
-					for i, arg := range cmd.Args() {
-						if i > 0 {
-							buf.WriteByte(' ')
-						}
-						buf.WriteString(mapping.Repr(arg))
+		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(' ')
 					}
-					logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
+					buf.WriteString(mapping.Repr(arg))
 				}
-			}()
+				logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
+			}
+		}()
 
-			return proc(cmd)
-		}
+		return proc(cmd)
 	}
 }
diff --git a/core/stores/redis/redis.go b/core/stores/redis/redis.go
index 63acb68c..3fa001c4 100644
--- a/core/stores/redis/redis.go
+++ b/core/stores/redis/redis.go
@@ -9,6 +9,7 @@ import (
 	red "github.com/go-redis/redis"
 	"github.com/tal-tech/go-zero/core/breaker"
 	"github.com/tal-tech/go-zero/core/mapping"
+	"github.com/tal-tech/go-zero/core/syncx"
 )
 
 const (
@@ -24,8 +25,11 @@ const (
 	defaultSlowThreshold = time.Millisecond * 100
 )
 
-// ErrNilNode is an error that indicates a nil redis node.
-var ErrNilNode = errors.New("nil redis node")
+var (
+	// ErrNilNode is an error that indicates a nil redis node.
+	ErrNilNode    = errors.New("nil redis node")
+	slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
+)
 
 type (
 	// Option defines the method to customize a Redis.
@@ -39,12 +43,11 @@ type (
 
 	// Redis defines a redis node/cluster. It is thread-safe.
 	Redis struct {
-		Addr          string
-		Type          string
-		Pass          string
-		tls           bool
-		brk           breaker.Breaker
-		slowThreshold time.Duration
+		Addr string
+		Type string
+		Pass string
+		tls  bool
+		brk  breaker.Breaker
 	}
 
 	// RedisNode interface represents a redis node.
@@ -78,10 +81,9 @@ type (
 // New returns a Redis with given options.
 func New(addr string, opts ...Option) *Redis {
 	r := &Redis{
-		Addr:          addr,
-		Type:          NodeType,
-		brk:           breaker.NewBreaker(),
-		slowThreshold: defaultSlowThreshold,
+		Addr: addr,
+		Type: NodeType,
+		brk:  breaker.NewBreaker(),
 	}
 
 	for _, opt := range opts {
@@ -1759,6 +1761,11 @@ func Cluster() Option {
 	}
 }
 
+// SetSlowThreshold sets the slow threshold.
+func SetSlowThreshold(threshold time.Duration) {
+	slowThreshold.Set(threshold)
+}
+
 // WithPass customizes the given Redis with given password.
 func WithPass(pass string) Option {
 	return func(r *Redis) {
@@ -1766,13 +1773,6 @@ func WithPass(pass string) Option {
 	}
 }
 
-// WithSlowThreshold sets the slow threshold.
-func WithSlowThreshold(threshold time.Duration) Option {
-	return func(r *Redis) {
-		r.slowThreshold = threshold
-	}
-}
-
 // WithTLS customizes the given Redis with TLS enabled.
 func WithTLS() Option {
 	return func(r *Redis) {
diff --git a/core/stores/redis/redisclientmanager.go b/core/stores/redis/redisclientmanager.go
index 943e85d5..5cf88c14 100644
--- a/core/stores/redis/redisclientmanager.go
+++ b/core/stores/redis/redisclientmanager.go
@@ -32,7 +32,7 @@ func getClient(r *Redis) (*red.Client, error) {
 			MinIdleConns: idleConns,
 			TLSConfig:    tlsConfig,
 		})
-		store.WrapProcess(checkDuration(r.slowThreshold))
+		store.WrapProcess(checkDuration)
 		return store, nil
 	})
 	if err != nil {
diff --git a/core/stores/redis/redisclustermanager.go b/core/stores/redis/redisclustermanager.go
index 722fb4fb..19e69c43 100644
--- a/core/stores/redis/redisclustermanager.go
+++ b/core/stores/redis/redisclustermanager.go
@@ -25,7 +25,7 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
 			MinIdleConns: idleConns,
 			TLSConfig:    tlsConfig,
 		})
-		store.WrapProcess(checkDuration(r.slowThreshold))
+		store.WrapProcess(checkDuration)
 
 		return store, nil
 	})


Test patch:
diff --git a/core/stores/redis/redis_test.go b/core/stores/redis/redis_test.go
index 8b5ec3f2..2f84e5de 100644
--- a/core/stores/redis/redis_test.go
+++ b/core/stores/redis/redis_test.go
@@ -1073,6 +1073,12 @@ func TestRedisGeo(t *testing.T) {
 	})
 }
 
+func TestSetSlowThreshold(t *testing.T) {
+	assert.Equal(t, defaultSlowThreshold, slowThreshold.Load())
+	SetSlowThreshold(time.Second)
+	assert.Equal(t, time.Second, slowThreshold.Load())
+}
+
 func TestRedis_WithPass(t *testing.T) {
 	runOnRedis(t, func(client *Redis) {
 		err := New(client.Addr, WithPass("any")).Ping()
@@ -1115,7 +1121,7 @@ func runOnRedisTLS(t *testing.T, fn func(client *Redis)) {
 			client.Close()
 		}
 	}()
-	fn(New(s.Addr(), WithTLS(), WithSlowThreshold(defaultSlowThreshold/2)))
+	fn(New(s.Addr(), WithTLS()))
 }
 
 func badType() Option {