125 lines
2.6 KiB
Go
125 lines
2.6 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
var (
|
|
Client *redis.Client
|
|
Enabled bool
|
|
memoryStore sync.Map // Redis 不可用时的内存降级存储
|
|
)
|
|
|
|
// Config Redis 配置
|
|
type Config struct {
|
|
Host string
|
|
Port string
|
|
Password string
|
|
DB int
|
|
}
|
|
|
|
// Init 初始化 Redis 连接,未开启或连接失败则降级为内存模式
|
|
func Init(cfg Config) {
|
|
if cfg.Host == "" {
|
|
log.Printf("[redis] Redis 未配置,已降级为内存模式运行")
|
|
Enabled = false
|
|
Client = nil
|
|
return
|
|
}
|
|
|
|
Client = redis.NewClient(&redis.Options{
|
|
Addr: fmt.Sprintf("%s:%s", cfg.Host, cfg.Port),
|
|
Password: cfg.Password,
|
|
DB: cfg.DB,
|
|
DialTimeout: 2 * time.Second,
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
|
|
if err := Client.Ping(ctx).Err(); err != nil {
|
|
log.Printf("[redis] Redis 没开或连接失败 (%v),已降级为内存模式运行", err)
|
|
Enabled = false
|
|
Client = nil
|
|
return
|
|
}
|
|
|
|
Enabled = true
|
|
log.Printf("[redis] Redis 连接成功: %s:%s (db=%d)", cfg.Host, cfg.Port, cfg.DB)
|
|
}
|
|
|
|
// Set 设置键值(带过期时间,0=不过期)
|
|
func Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
|
|
if Enabled && Client != nil {
|
|
return Client.Set(ctx, key, value, expiration).Err()
|
|
}
|
|
// 内存降级
|
|
memoryStore.Store(key, memoryItem{value: value, expireAt: time.Now().Add(expiration)})
|
|
return nil
|
|
}
|
|
|
|
// Get 获取值
|
|
func Get(ctx context.Context, key string) (string, error) {
|
|
if Enabled && Client != nil {
|
|
return Client.Get(ctx, key).Result()
|
|
}
|
|
// 内存降级
|
|
v, ok := memoryStore.Load(key)
|
|
if !ok {
|
|
return "", redis.Nil
|
|
}
|
|
item := v.(memoryItem)
|
|
if time.Now().After(item.expireAt) {
|
|
memoryStore.Delete(key)
|
|
return "", redis.Nil
|
|
}
|
|
return fmt.Sprintf("%v", item.value), nil
|
|
}
|
|
|
|
// Del 删除键
|
|
func Del(ctx context.Context, key string) error {
|
|
if Enabled && Client != nil {
|
|
return Client.Del(ctx, key).Err()
|
|
}
|
|
memoryStore.Delete(key)
|
|
return nil
|
|
}
|
|
|
|
// Exists 检查键是否存在
|
|
func Exists(ctx context.Context, key string) (int64, error) {
|
|
if Enabled && Client != nil {
|
|
return Client.Exists(ctx, key).Result()
|
|
}
|
|
_, ok := memoryStore.Load(key)
|
|
if ok {
|
|
return 1, nil
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
// Incr 自增
|
|
func Incr(ctx context.Context, key string) (int64, error) {
|
|
if Enabled && Client != nil {
|
|
return Client.Incr(ctx, key).Result()
|
|
}
|
|
// 内存降级(简单实现)
|
|
v, _ := Get(ctx, key)
|
|
var n int64
|
|
fmt.Sscanf(v, "%d", &n)
|
|
n++
|
|
Set(ctx, key, n, 0)
|
|
return n, nil
|
|
}
|
|
|
|
// memoryItem 内存存储项
|
|
type memoryItem struct {
|
|
value interface{}
|
|
expireAt time.Time
|
|
}
|