2025-11-28 23:30:49 +08:00
|
|
|
|
package redis
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"carrotskin/pkg/config"
|
|
|
|
|
|
"fmt"
|
2025-12-24 16:03:46 +08:00
|
|
|
|
"os"
|
2025-11-28 23:30:49 +08:00
|
|
|
|
"sync"
|
|
|
|
|
|
|
2025-12-24 16:03:46 +08:00
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
|
|
|
|
redis9 "github.com/redis/go-redis/v9"
|
2025-11-28 23:30:49 +08:00
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
|
// clientInstance 全局Redis客户端实例
|
|
|
|
|
|
clientInstance *Client
|
|
|
|
|
|
// once 确保只初始化一次
|
|
|
|
|
|
once sync.Once
|
|
|
|
|
|
// initError 初始化错误
|
|
|
|
|
|
initError error
|
2025-12-24 16:03:46 +08:00
|
|
|
|
// miniredisInstance 用于测试/开发环境
|
|
|
|
|
|
miniredisInstance *miniredis.Miniredis
|
2025-11-28 23:30:49 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Init 初始化Redis客户端(线程安全,只会执行一次)
|
2025-12-24 16:03:46 +08:00
|
|
|
|
// 如果Redis连接失败且环境为测试/开发,则回退到miniredis
|
2025-11-28 23:30:49 +08:00
|
|
|
|
func Init(cfg config.RedisConfig, logger *zap.Logger) error {
|
2025-12-24 16:03:46 +08:00
|
|
|
|
var err error
|
2025-11-28 23:30:49 +08:00
|
|
|
|
once.Do(func() {
|
2025-12-24 16:03:46 +08:00
|
|
|
|
// 尝试连接真实Redis
|
|
|
|
|
|
clientInstance, err = New(cfg, logger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Warn("Redis连接失败,尝试使用miniredis回退", zap.Error(err))
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否允许回退到miniredis(仅开发/测试环境)
|
|
|
|
|
|
if allowFallbackToMiniRedis() {
|
|
|
|
|
|
clientInstance, err = initMiniRedis(logger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
initError = fmt.Errorf("Redis和miniredis都初始化失败: %w", err)
|
|
|
|
|
|
logger.Error("miniredis初始化失败", zap.Error(initError))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
logger.Info("已回退到miniredis用于开发/测试环境")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
initError = fmt.Errorf("Redis连接失败且不允许回退: %w", err)
|
|
|
|
|
|
logger.Error("Redis连接失败", zap.Error(initError))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-11-28 23:30:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return initError
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-24 16:03:46 +08:00
|
|
|
|
// allowFallbackToMiniRedis 检查是否允许回退到miniredis
|
|
|
|
|
|
func allowFallbackToMiniRedis() bool {
|
|
|
|
|
|
// 检查环境变量
|
|
|
|
|
|
env := os.Getenv("ENVIRONMENT")
|
|
|
|
|
|
return env == "development" || env == "test" || env == "dev" ||
|
|
|
|
|
|
os.Getenv("USE_MINIREDIS") == "true"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initMiniRedis 初始化miniredis(用于开发/测试环境)
|
|
|
|
|
|
func initMiniRedis(logger *zap.Logger) (*Client, error) {
|
|
|
|
|
|
var err error
|
|
|
|
|
|
miniredisInstance, err = miniredis.Run()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("启动miniredis失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建Redis客户端连接到miniredis
|
|
|
|
|
|
redisClient := redis9.NewClient(&redis9.Options{
|
|
|
|
|
|
Addr: miniredisInstance.Addr(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
client := &Client{
|
|
|
|
|
|
Client: redisClient,
|
|
|
|
|
|
logger: logger,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
logger.Info("miniredis已启动", zap.String("addr", miniredisInstance.Addr()))
|
|
|
|
|
|
return client, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-28 23:30:49 +08:00
|
|
|
|
// GetClient 获取Redis客户端实例(线程安全)
|
|
|
|
|
|
func GetClient() (*Client, error) {
|
|
|
|
|
|
if clientInstance == nil {
|
|
|
|
|
|
return nil, fmt.Errorf("Redis客户端未初始化,请先调用 redis.Init()")
|
|
|
|
|
|
}
|
|
|
|
|
|
return clientInstance, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MustGetClient 获取Redis客户端实例,如果未初始化则panic
|
|
|
|
|
|
func MustGetClient() *Client {
|
|
|
|
|
|
client, err := GetClient()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
return client
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-24 16:03:46 +08:00
|
|
|
|
// Close 关闭Redis连接(包括miniredis如果使用了)
|
|
|
|
|
|
func Close() error {
|
|
|
|
|
|
var err error
|
|
|
|
|
|
if miniredisInstance != nil {
|
|
|
|
|
|
miniredisInstance.Close()
|
|
|
|
|
|
miniredisInstance = nil
|
|
|
|
|
|
}
|
|
|
|
|
|
if clientInstance != nil {
|
|
|
|
|
|
err = clientInstance.Close()
|
|
|
|
|
|
clientInstance = nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2025-11-28 23:30:49 +08:00
|
|
|
|
|
2025-12-24 16:03:46 +08:00
|
|
|
|
// IsUsingMiniRedis 检查是否使用了miniredis
|
|
|
|
|
|
func IsUsingMiniRedis() bool {
|
|
|
|
|
|
return miniredisInstance != nil
|
|
|
|
|
|
}
|