From 91a5a7d6120f4789a1868a5e1df230d451a8a016 Mon Sep 17 00:00:00 2001 From: charlie <3140647@qq.com> Date: Thu, 26 Oct 2023 14:42:56 +0800 Subject: [PATCH] update --- calendar/output.go | 24 ++++++++++++ errors/error.go | 2 + go.mod | 2 +- go.sum | 2 + redis/redis.go | 91 +++++++++++++++++++++++++++++++++++--------- redis/redis_test.go | 16 ++++++++ redis/rename_hook.go | 6 +-- tests/redis.go | 70 +++++++++++++++++++--------------- 8 files changed, 160 insertions(+), 53 deletions(-) diff --git a/calendar/output.go b/calendar/output.go index 2ca666d..b63fcf8 100644 --- a/calendar/output.go +++ b/calendar/output.go @@ -53,6 +53,30 @@ const ( ShortTimeNanoLayout = "150405.999999999" ) +func String(t time.Time) string { + return ToDateTimeString(t) +} + +func ToDateTimeString(t time.Time) string { + return Create(t).ToDateTimeString() +} + +func Format(t time.Time, layout string) string { + return Create(t).Format(layout) +} + +func ToDateTimeInt(t time.Time) int { + return Create(t).ToDateTimeInt() +} + +func ToShortDateInt(t time.Time) int { + return Create(t).ToShortDateInt() +} + +func ToMonthInt(t time.Time) int { + return Create(t).ToMonthInt() +} + func (c Calendar) String() string { return c.ToDateTimeString() } diff --git a/errors/error.go b/errors/error.go index 4dad400..411e85c 100644 --- a/errors/error.go +++ b/errors/error.go @@ -12,6 +12,8 @@ const ( defaultErrorCode = "999999" ) +var NotImplemented = errors.New("Not Implemented") + type Error interface { Wraped() []error Code() string diff --git a/go.mod b/go.mod index 61129ea..e5cf085 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/allegro/bigcache/v3 v3.1.0 github.com/alphadose/haxmap v1.3.0 github.com/antonfisher/nested-logrus-formatter v1.3.1 - github.com/bits-and-blooms/bitset v1.9.0 + github.com/bits-and-blooms/bitset v1.10.0 github.com/cespare/xxhash/v2 v2.2.0 github.com/coocood/freecache v1.2.4 github.com/dlclark/regexp2 v1.10.0 diff --git a/go.sum b/go.sum index faeb4dd..e9b9038 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UME github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= github.com/bits-and-blooms/bitset v1.9.0 h1:g1YivPG8jOtrN013Fe8OBXubkiTwvm7/vG2vXz03ANU= github.com/bits-and-blooms/bitset v1.9.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= diff --git a/redis/redis.go b/redis/redis.go index 0093b3a..9cefccc 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -1,7 +1,9 @@ package redis import ( - "sync" + "context" + "fmt" + "strings" "time" "github.com/charlienet/go-mixed/expr" @@ -13,16 +15,13 @@ const ( blockingQueryTimeout = 5 * time.Second readWriteTimeout = 2 * time.Second - defaultSlowThreshold = time.Millisecond * 100 // 慢查询 + defaultSlowThreshold = "5000" // 慢查询(单位微秒) ) var Nil = redis.Nil -var ( - once sync.Once -) - type ReidsOption struct { + Addr string Addrs []string Password string // 密码 Prefix string @@ -41,6 +40,9 @@ type ReidsOption struct { WriteTimeout time.Duration ContextTimeoutEnabled bool + // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO). + PoolFIFO bool + PoolSize int PoolTimeout time.Duration MinIdleConns int @@ -49,14 +51,36 @@ type ReidsOption struct { ConnMaxLifetime time.Duration } +var _ Client = redisClient{} + type Client interface { redis.UniversalClient + Prefix() string + Separator() string + JoinKeys(keys ...string) string + FormatKeys(keys ...string) []string } -func New(opt *ReidsOption) Client { - var rdb redis.UniversalClient - once.Do(func() { - rdb = redis.NewUniversalClient(&redis.UniversalOptions{ +type redisClient struct { + redis.UniversalClient + prefix string + separator string +} + +func New(opt *ReidsOption) redisClient { + var rdb redisClient + + if len(opt.Addrs) == 0 && len(opt.Addr) > 0 { + opt.Addrs = []string{opt.Addr} + } + + separator := expr.Ternary(len(opt.Separator) == 0, defaultSeparator, opt.Separator) + prefix := expr.Ternary(len(opt.Prefix) > 0, fmt.Sprintf("%s%s", opt.Prefix, separator), "") + + rdb = redisClient{ + prefix: prefix, + separator: separator, + UniversalClient: redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: opt.Addrs, Password: opt.Password, @@ -77,15 +101,46 @@ func New(opt *ReidsOption) Client { MaxIdleConns: opt.MaxIdleConns, ConnMaxIdleTime: opt.ConnMaxIdleTime, ConnMaxLifetime: opt.ConnMaxLifetime, - }) + })} - if len(opt.Prefix) > 0 { - rdb.AddHook(renameKey{ - prefix: opt.Prefix, - separator: expr.Ternary(len(opt.Separator) == 0, defaultSeparator, opt.Separator), - }) - } - }) + rdb.ConfigSet(context.Background(), "slowlog-log-slower-than", defaultSlowThreshold) + + if len(opt.Prefix) > 0 { + rdb.AddHook(renameKey{ + prefix: prefix, + }) + } return rdb } + +func (rdb redisClient) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd { + newKeys := rdb.FormatKeys(keys...) + + return rdb.UniversalClient.Eval(ctx, script, newKeys, args...) +} + +func (rdb redisClient) Prefix() string { + return rdb.prefix +} + +func (rdb redisClient) Separator() string { + return rdb.separator +} + +func (rdb redisClient) JoinKeys(keys ...string) string { + return strings.Join(keys, rdb.separator) +} + +func (rdb redisClient) FormatKeys(keys ...string) []string { + if len(rdb.prefix) == 0 { + return keys + } + + re := make([]string, 0, len(keys)) + for _, k := range keys { + re = append(re, fmt.Sprintf("%s%s", rdb.prefix, k)) + } + + return re +} diff --git a/redis/redis_test.go b/redis/redis_test.go index 54c99ec..44adbc0 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -3,6 +3,7 @@ package redis_test import ( "context" "fmt" + "strconv" "sync" "testing" "time" @@ -133,3 +134,18 @@ func TestPubSub(t *testing.T) { }) } +func TestRedisPool(t *testing.T) { + tests.RunOnRedis(t, func(client redis.Client) { + defer client.Close() + + err := client.ConfigSet(context.Background(), "slowlog-log-slower-than", strconv.FormatInt(int64(time.Microsecond)*5, 10)).Err() + assert.Nil(t, err, err) + + t.Log(client.ConfigGet(context.Background(), "slowlog-log-slower-than").Result()) + + }, redis.ReidsOption{ + Addr: "192.168.123.100:6379", + PoolSize: 100, + PoolFIFO: true, + }) +} diff --git a/redis/rename_hook.go b/redis/rename_hook.go index a8ac84c..ca8ad2b 100644 --- a/redis/rename_hook.go +++ b/redis/rename_hook.go @@ -34,9 +34,7 @@ func (r renameKey) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.Pro func (r renameKey) ProcessHook(next redis.ProcessHook) redis.ProcessHook { return func(ctx context.Context, cmd redis.Cmder) error { r.renameKey(cmd) - next(ctx, cmd) - - return nil + return next(ctx, cmd) } } @@ -51,7 +49,7 @@ func (r renameKey) renameKey(cmd redis.Cmder) { } switch strings.ToUpper(cmd.Name()) { - case "SELECT": + case "SELECT", "EVAL": // 无KEY指令 case "RENAME", "RENAMENX", diff --git a/tests/redis.go b/tests/redis.go index 26072c1..c3b0468 100644 --- a/tests/redis.go +++ b/tests/redis.go @@ -3,7 +3,6 @@ package tests import ( "context" "log" - "testing" "time" "github.com/alicebob/miniredis/v2" @@ -11,28 +10,36 @@ import ( "github.com/stretchr/testify/assert" ) -func RunOnSpecifiedRedis(t *testing.T, fn func(client redis.Client), addr ...string) { - rdb := redis.New(&redis.ReidsOption{ - Addrs: addr, - }) - defer rdb.Close() +func RunOnRedis(t assert.TestingT, fn func(rdb redis.Client), opt ...redis.ReidsOption) { + var redis redis.Client + var clean func() + var err error - if err := rdb.Ping(context.Background()).Err(); err != nil { - t.Fatal(err) - } - - fn(rdb) -} - -func RunOnRedis(t *testing.T, fn func(client redis.Client)) { - redis, clean, err := createMiniRedis() - assert.Nil(t, err) + redis, clean, err = CreateRedis(opt...) + assert.Nil(t, err, err) defer clean() - fn(redis) } +func CreateRedis(opt ...redis.ReidsOption) (r redis.Client, clean func(), err error) { + if len(opt) > 0 { + return createRedisClient(opt[0]) + } else { + return createMiniRedis() + } +} + +func createRedisClient(opt redis.ReidsOption) (r redis.Client, clean func(), err error) { + rdb := redis.New(&opt) + + if err := rdb.Ping(context.Background()).Err(); err != nil { + return nil, nil, err + } + + return rdb, func() { rdb.Close() }, nil +} + func createMiniRedis() (r redis.Client, clean func(), err error) { mr, err := miniredis.Run() if err != nil { @@ -42,19 +49,22 @@ func createMiniRedis() (r redis.Client, clean func(), err error) { addr := mr.Addr() log.Println("mini redis run at:", addr) - return redis.New(&redis.ReidsOption{ - Addrs: []string{addr}, - }), func() { - ch := make(chan struct{}) + rdb := redis.New(&redis.ReidsOption{ + Addrs: []string{addr}, + }) - go func() { - mr.Close() - close(ch) - }() + return rdb, func() { + ch := make(chan struct{}) - select { - case <-ch: - case <-time.After(time.Second): - } - }, nil + go func() { + rdb.Close() + mr.Close() + close(ch) + }() + + select { + case <-ch: + case <-time.After(time.Second * 5): + } + }, nil }