1
0
mirror of https://github.com/charlienet/go-mixed.git synced 2025-07-17 08:02:40 +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"
)
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()
}

View File

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

2
go.mod
View File

@ -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

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/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=

View File

@ -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
}

View File

@ -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,
})
}

View File

@ -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",

View File

@ -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
}