mirror of
https://github.com/charlienet/go-mixed.git
synced 2025-07-17 08:02:40 +08:00
update
This commit is contained in:
@ -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()
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ const (
|
||||
defaultErrorCode = "999999"
|
||||
)
|
||||
|
||||
var NotImplemented = errors.New("Not Implemented")
|
||||
|
||||
type Error interface {
|
||||
Wraped() []error
|
||||
Code() string
|
||||
|
2
go.mod
2
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
|
||||
|
2
go.sum
2
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=
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user