first commit
This commit is contained in:
482
pkg/cache/redis.go
vendored
Normal file
482
pkg/cache/redis.go
vendored
Normal file
@ -0,0 +1,482 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.bvbej.com/bvbej/base-golang/pkg/time_parse"
|
||||
"git.bvbej.com/bvbej/base-golang/pkg/trace"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
type Trace = trace.T
|
||||
|
||||
type option struct {
|
||||
Trace *trace.Trace
|
||||
Redis *trace.Redis
|
||||
}
|
||||
|
||||
type RedisConfig struct {
|
||||
Addr string `yaml:"addr"`
|
||||
Pass string `yaml:"pass"`
|
||||
DB int `yaml:"db"`
|
||||
MaxRetries int `yaml:"maxRetries"` // 最大重试次数
|
||||
PoolSize int `yaml:"poolSize"` // Redis连接池大小
|
||||
MinIdleConn int `yaml:"minIdleConn"` // 最小空闲连接数
|
||||
}
|
||||
|
||||
func newOption() *option {
|
||||
return &option{}
|
||||
}
|
||||
|
||||
var _ Repo = (*cacheRepo)(nil)
|
||||
|
||||
type Repo interface {
|
||||
i()
|
||||
Client() *redis.Client
|
||||
Set(key, value string, ttl time.Duration, options ...Option) error
|
||||
Get(key string, options ...Option) (string, error)
|
||||
TTL(key string) (time.Duration, error)
|
||||
Expire(key string, ttl time.Duration) bool
|
||||
ExpireAt(key string, ttl time.Time) bool
|
||||
Del(key string, options ...Option) bool
|
||||
Exists(keys ...string) bool
|
||||
Incr(key string, options ...Option) (int64, error)
|
||||
Decr(key string, options ...Option) (int64, error)
|
||||
HGet(key, field string, options ...Option) (string, error)
|
||||
HSet(key, field, value string, options ...Option) error
|
||||
HDel(key, field string, options ...Option) error
|
||||
HGetAll(key string, options ...Option) (map[string]string, error)
|
||||
HIncrBy(key, field string, incr int64, options ...Option) (int64, error)
|
||||
HIncrByFloat(key, field string, incr float64, options ...Option) (float64, error)
|
||||
LPush(key, value string, options ...Option) error
|
||||
LLen(key string, options ...Option) (int64, error)
|
||||
BRPop(key string, timeout time.Duration, options ...Option) (string, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
type cacheRepo struct {
|
||||
client *redis.Client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func New(cfg RedisConfig) (Repo, error) {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.Addr,
|
||||
Password: cfg.Pass,
|
||||
DB: cfg.DB,
|
||||
MaxRetries: cfg.MaxRetries,
|
||||
PoolSize: cfg.PoolSize,
|
||||
MinIdleConns: cfg.MinIdleConn,
|
||||
})
|
||||
ctx := context.TODO()
|
||||
if err := client.Ping(ctx).Err(); err != nil {
|
||||
return nil, errors.Join(err, errors.New("ping redis err"))
|
||||
}
|
||||
return &cacheRepo{
|
||||
client: client,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func WithTrace(t Trace) Option {
|
||||
return func(opt *option) {
|
||||
if t != nil {
|
||||
opt.Trace = t.(*trace.Trace)
|
||||
opt.Redis = new(trace.Redis)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cacheRepo) i() {}
|
||||
|
||||
func (c *cacheRepo) Client() *redis.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Set(key, value string, ttl time.Duration, options ...Option) error {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "set"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = value
|
||||
opt.Redis.TTL = ttl.Minutes()
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if err := c.client.Set(c.ctx, key, value, ttl).Err(); err != nil {
|
||||
return errors.Join(err, fmt.Errorf("redis set key: %s err", key))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Get(key string, options ...Option) (string, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "get"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.Get(c.ctx, key).Result()
|
||||
if err != nil {
|
||||
return "", errors.Join(err, fmt.Errorf("redis get key: %s err", key))
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) TTL(key string) (time.Duration, error) {
|
||||
ttl, err := c.client.TTL(c.ctx, key).Result()
|
||||
if err != nil {
|
||||
return -1, errors.Join(err, fmt.Errorf("redis get key: %s err", key))
|
||||
}
|
||||
|
||||
return ttl, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Expire(key string, ttl time.Duration) bool {
|
||||
ok, _ := c.client.Expire(c.ctx, key, ttl).Result()
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *cacheRepo) ExpireAt(key string, ttl time.Time) bool {
|
||||
ok, _ := c.client.ExpireAt(c.ctx, key, ttl).Result()
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Exists(keys ...string) bool {
|
||||
if len(keys) == 0 {
|
||||
return true
|
||||
}
|
||||
value, _ := c.client.Exists(c.ctx, keys...).Result()
|
||||
return value > 0
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Del(key string, options ...Option) bool {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "del"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if key == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
value, _ := c.client.Del(c.ctx, key).Result()
|
||||
return value > 0
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Incr(key string, options ...Option) (int64, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "incr"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
value, err := c.client.Incr(c.ctx, key).Result()
|
||||
if err != nil {
|
||||
return 0, errors.Join(err, fmt.Errorf("redis incr key: %s err", key))
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Decr(key string, options ...Option) (int64, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "decr"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
value, err := c.client.Decr(c.ctx, key).Result()
|
||||
if err != nil {
|
||||
return 0, errors.Join(err, fmt.Errorf("redis decr key: %s err", key))
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) HGet(key, field string, options ...Option) (string, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "hash get"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = field
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.HGet(c.ctx, key, field).Result()
|
||||
if err != nil {
|
||||
return "", errors.Join(err, fmt.Errorf("redis hget key: %s field: %s err", key, field))
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) HSet(key, field, value string, options ...Option) error {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "hash set"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = field + "/" + value
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if err := c.client.HSet(c.ctx, key, field, value).Err(); err != nil {
|
||||
return errors.Join(err, fmt.Errorf("redis hset key: %s field: %s err", key, field))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) HDel(key, field string, options ...Option) error {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "hash del"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = field
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if err := c.client.HDel(c.ctx, key, field).Err(); err != nil {
|
||||
return errors.Join(err, fmt.Errorf("redis hdel key: %s field: %s err", key, field))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) HGetAll(key string, options ...Option) (map[string]string, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "hash get all"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.HGetAll(c.ctx, key).Result()
|
||||
if err != nil {
|
||||
return nil, errors.Join(err, fmt.Errorf("redis hget all key: %s err", key))
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) HIncrBy(key, field string, incr int64, options ...Option) (int64, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "hash incr int64"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = fmt.Sprintf("field:%s incr:%d", field, incr)
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.HIncrBy(c.ctx, key, field, incr).Result()
|
||||
if err != nil {
|
||||
return 0, errors.Join(err, fmt.Errorf("redis hash incr int64 key: %s err", key))
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) HIncrByFloat(key, field string, incr float64, options ...Option) (float64, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "hash incr float64"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = fmt.Sprintf("field:%s incr:%d", field, incr)
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.HIncrByFloat(c.ctx, key, field, incr).Result()
|
||||
if err != nil {
|
||||
return 0, errors.Join(err, fmt.Errorf("redis hash incr float64 key: %s err", key))
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) LPush(key, value string, options ...Option) error {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "list push"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = value
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
_, err := c.client.LPush(c.ctx, key, value).Result()
|
||||
if err != nil {
|
||||
return errors.Join(err, fmt.Errorf("redis list push key: %s value: %s err", key, value))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) LLen(key string, options ...Option) (int64, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "list len"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.LLen(c.ctx, key).Result()
|
||||
if err != nil {
|
||||
return 0, errors.Join(err, fmt.Errorf("redis list len key: %s err", key))
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) BRPop(key string, timeout time.Duration, options ...Option) (string, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "list brpop"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.TTL = timeout.Seconds()
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.BRPop(c.ctx, timeout, key).Result()
|
||||
if err != nil {
|
||||
return "", errors.Join(err, fmt.Errorf("redis list len key: %s err", key))
|
||||
}
|
||||
|
||||
return value[1], nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Close() error {
|
||||
return c.client.Close()
|
||||
}
|
Reference in New Issue
Block a user