1
0
mirror of https://github.com/charlienet/go-mixed.git synced 2025-07-18 00:22:41 +08:00
This commit is contained in:
2023-10-26 14:42:56 +08:00
parent 0d124c0b79
commit 91a5a7d612
8 changed files with 160 additions and 53 deletions

View File

@ -53,6 +53,30 @@ const (
ShortTimeNanoLayout = "150405.999999999" 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 { func (c Calendar) String() string {
return c.ToDateTimeString() return c.ToDateTimeString()
} }

View File

@ -12,6 +12,8 @@ const (
defaultErrorCode = "999999" defaultErrorCode = "999999"
) )
var NotImplemented = errors.New("Not Implemented")
type Error interface { type Error interface {
Wraped() []error Wraped() []error
Code() string Code() string

2
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/allegro/bigcache/v3 v3.1.0 github.com/allegro/bigcache/v3 v3.1.0
github.com/alphadose/haxmap v1.3.0 github.com/alphadose/haxmap v1.3.0
github.com/antonfisher/nested-logrus-formatter v1.3.1 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/cespare/xxhash/v2 v2.2.0
github.com/coocood/freecache v1.2.4 github.com/coocood/freecache v1.2.4
github.com/dlclark/regexp2 v1.10.0 github.com/dlclark/regexp2 v1.10.0

2
go.sum
View File

@ -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/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 h1:g1YivPG8jOtrN013Fe8OBXubkiTwvm7/vG2vXz03ANU=
github.com/bits-and-blooms/bitset v1.9.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 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 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=

View File

@ -1,7 +1,9 @@
package redis package redis
import ( import (
"sync" "context"
"fmt"
"strings"
"time" "time"
"github.com/charlienet/go-mixed/expr" "github.com/charlienet/go-mixed/expr"
@ -13,16 +15,13 @@ const (
blockingQueryTimeout = 5 * time.Second blockingQueryTimeout = 5 * time.Second
readWriteTimeout = 2 * time.Second readWriteTimeout = 2 * time.Second
defaultSlowThreshold = time.Millisecond * 100 // 慢查询 defaultSlowThreshold = "5000" // 慢查询(单位微秒)
) )
var Nil = redis.Nil var Nil = redis.Nil
var (
once sync.Once
)
type ReidsOption struct { type ReidsOption struct {
Addr string
Addrs []string Addrs []string
Password string // 密码 Password string // 密码
Prefix string Prefix string
@ -41,6 +40,9 @@ type ReidsOption struct {
WriteTimeout time.Duration WriteTimeout time.Duration
ContextTimeoutEnabled bool ContextTimeoutEnabled bool
// PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
PoolFIFO bool
PoolSize int PoolSize int
PoolTimeout time.Duration PoolTimeout time.Duration
MinIdleConns int MinIdleConns int
@ -49,14 +51,36 @@ type ReidsOption struct {
ConnMaxLifetime time.Duration ConnMaxLifetime time.Duration
} }
var _ Client = redisClient{}
type Client interface { type Client interface {
redis.UniversalClient redis.UniversalClient
Prefix() string
Separator() string
JoinKeys(keys ...string) string
FormatKeys(keys ...string) []string
} }
func New(opt *ReidsOption) Client { type redisClient struct {
var rdb redis.UniversalClient redis.UniversalClient
once.Do(func() { prefix string
rdb = redis.NewUniversalClient(&redis.UniversalOptions{ 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, Addrs: opt.Addrs,
Password: opt.Password, Password: opt.Password,
@ -77,15 +101,46 @@ func New(opt *ReidsOption) Client {
MaxIdleConns: opt.MaxIdleConns, MaxIdleConns: opt.MaxIdleConns,
ConnMaxIdleTime: opt.ConnMaxIdleTime, ConnMaxIdleTime: opt.ConnMaxIdleTime,
ConnMaxLifetime: opt.ConnMaxLifetime, ConnMaxLifetime: opt.ConnMaxLifetime,
}) })}
rdb.ConfigSet(context.Background(), "slowlog-log-slower-than", defaultSlowThreshold)
if len(opt.Prefix) > 0 { if len(opt.Prefix) > 0 {
rdb.AddHook(renameKey{ rdb.AddHook(renameKey{
prefix: opt.Prefix, prefix: prefix,
separator: expr.Ternary(len(opt.Separator) == 0, defaultSeparator, opt.Separator),
}) })
} }
})
return rdb 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
}

View File

@ -3,6 +3,7 @@ package redis_test
import ( import (
"context" "context"
"fmt" "fmt"
"strconv"
"sync" "sync"
"testing" "testing"
"time" "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,
})
}

View File

@ -34,9 +34,7 @@ func (r renameKey) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.Pro
func (r renameKey) ProcessHook(next redis.ProcessHook) redis.ProcessHook { func (r renameKey) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
return func(ctx context.Context, cmd redis.Cmder) error { return func(ctx context.Context, cmd redis.Cmder) error {
r.renameKey(cmd) r.renameKey(cmd)
next(ctx, cmd) return next(ctx, cmd)
return nil
} }
} }
@ -51,7 +49,7 @@ func (r renameKey) renameKey(cmd redis.Cmder) {
} }
switch strings.ToUpper(cmd.Name()) { switch strings.ToUpper(cmd.Name()) {
case "SELECT": case "SELECT", "EVAL":
// 无KEY指令 // 无KEY指令
case case
"RENAME", "RENAMENX", "RENAME", "RENAMENX",

View File

@ -3,7 +3,6 @@ package tests
import ( import (
"context" "context"
"log" "log"
"testing"
"time" "time"
"github.com/alicebob/miniredis/v2" "github.com/alicebob/miniredis/v2"
@ -11,28 +10,36 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func RunOnSpecifiedRedis(t *testing.T, fn func(client redis.Client), addr ...string) { func RunOnRedis(t assert.TestingT, fn func(rdb redis.Client), opt ...redis.ReidsOption) {
rdb := redis.New(&redis.ReidsOption{ var redis redis.Client
Addrs: addr, var clean func()
}) var err error
defer rdb.Close()
if err := rdb.Ping(context.Background()).Err(); err != nil { redis, clean, err = CreateRedis(opt...)
t.Fatal(err) assert.Nil(t, err, err)
}
fn(rdb)
}
func RunOnRedis(t *testing.T, fn func(client redis.Client)) {
redis, clean, err := createMiniRedis()
assert.Nil(t, err)
defer clean() defer clean()
fn(redis) 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) { func createMiniRedis() (r redis.Client, clean func(), err error) {
mr, err := miniredis.Run() mr, err := miniredis.Run()
if err != nil { if err != nil {
@ -42,19 +49,22 @@ func createMiniRedis() (r redis.Client, clean func(), err error) {
addr := mr.Addr() addr := mr.Addr()
log.Println("mini redis run at:", addr) log.Println("mini redis run at:", addr)
return redis.New(&redis.ReidsOption{ rdb := redis.New(&redis.ReidsOption{
Addrs: []string{addr}, Addrs: []string{addr},
}), func() { })
return rdb, func() {
ch := make(chan struct{}) ch := make(chan struct{})
go func() { go func() {
rdb.Close()
mr.Close() mr.Close()
close(ch) close(ch)
}() }()
select { select {
case <-ch: case <-ch:
case <-time.After(time.Second): case <-time.After(time.Second * 5):
} }
}, nil }, nil
} }