This commit is contained in:
Joe
2026-01-16 15:49:34 +08:00
commit 550d3e1f42
380 changed files with 62024 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
package utils
import (
"context"
"fmt"
"sync"
"time"
"github.com/goravel/framework/facades"
"github.com/redis/go-redis/v9"
)
var (
// redisClients 缓存不同连接名的 Redis 客户端
redisClients sync.Map
// redisMutex 用于保护客户端创建过程
redisMutex sync.Mutex
)
// GetRedisClient 获取 Redis 客户端(使用连接池,支持多连接)
// connectionName: Redis 连接名称,默认为 "default"
// 返回缓存的 Redis 客户端,如果不存在则创建并缓存
func GetRedisClient(connectionName string) (*redis.Client, error) {
if connectionName == "" {
connectionName = "default"
}
// 先从缓存中获取
if client, ok := redisClients.Load(connectionName); ok {
redisClient := client.(*redis.Client)
// 测试连接是否有效
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
err := redisClient.Ping(ctx).Err()
cancel()
if err == nil {
return redisClient, nil
}
// 连接失效,从缓存中移除
redisClients.Delete(connectionName)
}
// 使用互斥锁确保只创建一个客户端
redisMutex.Lock()
defer redisMutex.Unlock()
// 双重检查,防止并发创建
if client, ok := redisClients.Load(connectionName); ok {
return client.(*redis.Client), nil
}
// 创建新的 Redis 客户端
client, err := createRedisClient(connectionName)
if err != nil {
return nil, err
}
// 缓存客户端
redisClients.Store(connectionName, client)
return client, nil
}
// createRedisClient 创建 Redis 客户端
func createRedisClient(connectionName string) (*redis.Client, error) {
// 获取 Redis 配置
host := facades.Config().GetString(fmt.Sprintf("database.redis.%s.host", connectionName), "")
if host == "" {
// 尝试使用 default 连接
host = facades.Config().GetString("database.redis.default.host", "127.0.0.1")
}
port := facades.Config().GetInt(fmt.Sprintf("database.redis.%s.port", connectionName), 0)
if port == 0 {
port = facades.Config().GetInt("database.redis.default.port", 6379)
}
password := facades.Config().GetString(fmt.Sprintf("database.redis.%s.password", connectionName), "")
if password == "" {
password = facades.Config().GetString("database.redis.default.password", "")
}
db := facades.Config().GetInt(fmt.Sprintf("database.redis.%s.database", connectionName), -1)
if db == -1 {
db = facades.Config().GetInt("database.redis.default.database", 0)
}
// 创建 Redis 客户端(使用连接池配置)
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", host, port),
Password: password,
DB: db,
PoolSize: 10, // 连接池大小
MinIdleConns: 5, // 最小空闲连接数
MaxRetries: 3, // 最大重试次数
})
// 测试连接(设置超时)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
_, err := client.Ping(ctx).Result()
if err != nil {
client.Close() // 连接失败,关闭客户端
return nil, fmt.Errorf("Redis 连接失败 [%s]: %v", connectionName, err)
}
return client, nil
}
// CloseRedisClient 关闭指定的 Redis 客户端并从缓存中移除
func CloseRedisClient(connectionName string) error {
if connectionName == "" {
connectionName = "default"
}
if client, ok := redisClients.LoadAndDelete(connectionName); ok {
redisClient := client.(*redis.Client)
return redisClient.Close()
}
return nil
}
// CloseAllRedisClients 关闭所有缓存的 Redis 客户端
func CloseAllRedisClients() error {
var errs []error
redisClients.Range(func(key, value any) bool {
client := value.(*redis.Client)
if err := client.Close(); err != nil {
errs = append(errs, err)
}
redisClients.Delete(key)
return true
})
if len(errs) > 0 {
return fmt.Errorf("关闭 Redis 客户端时发生错误: %v", errs)
}
return nil
}