mirror of
https://github.com/charlienet/go-mixed.git
synced 2025-07-17 16:12:42 +08:00
update
This commit is contained in:
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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
2
go.mod
@ -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
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/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=
|
||||||
|
@ -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,
|
||||||
})
|
})}
|
||||||
|
|
||||||
if len(opt.Prefix) > 0 {
|
rdb.ConfigSet(context.Background(), "slowlog-log-slower-than", defaultSlowThreshold)
|
||||||
rdb.AddHook(renameKey{
|
|
||||||
prefix: opt.Prefix,
|
if len(opt.Prefix) > 0 {
|
||||||
separator: expr.Ternary(len(opt.Separator) == 0, defaultSeparator, opt.Separator),
|
rdb.AddHook(renameKey{
|
||||||
})
|
prefix: prefix,
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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() {
|
})
|
||||||
ch := make(chan struct{})
|
|
||||||
|
|
||||||
go func() {
|
return rdb, func() {
|
||||||
mr.Close()
|
ch := make(chan struct{})
|
||||||
close(ch)
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
go func() {
|
||||||
case <-ch:
|
rdb.Close()
|
||||||
case <-time.After(time.Second):
|
mr.Close()
|
||||||
}
|
close(ch)
|
||||||
}, nil
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ch:
|
||||||
|
case <-time.After(time.Second * 5):
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user