0c9f256dfc
对应体检报告 #10-#24,一次性完成 v1.1.0 全部 13 项: - #10 storage/cache/redis/jwt/logger 五组件 Manager 化(XxxManager + DefaultXxx + SetDefaultXxxManager,包级 facade 保留兼容) - #11 删除 wire 包 + 清理 StartServerWithPort/GracefulShutdown 双轨 - #12 Lifecycle Hooks(OnInit/OnStart/OnReady/OnStop) - #13 Server 参数配置化(timeout/TLS/unix_socket/response_mode) - #14 JWTConfig.Expire 改 time.Duration + 删 AppConfig.TokenExpire - #15 response Mode 开关(ModeBusiness/ModeREST) - #16 Config.Validate 启动期校验 - #17 livez/readyz 探针路由 - #18 Prometheus metrics 中间件 + /metrics - #19 请求级 Timeout 中间件 - #21 主库探活 + replica 健康剔除 - #22 App.Go + in-flight goroutine 管理 - #24 RequestID 默认装入 + #23 核对 Breaking:删 wire、删 TokenExpire、JWTConfig.Expire 类型变更、删双轨函数。 详见 CHANGELOG 升级说明。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
118 lines
2.8 KiB
Go
118 lines
2.8 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/EthanCodeCraft/xlgo-core/config"
|
|
"github.com/EthanCodeCraft/xlgo-core/logger"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// RedisClient 全局 Redis 客户端(兼容 facade,由 RedisManager.Init 同步维护)。
|
|
// 保留供存量代码直接访问;新代码建议用 GetRedis() 或持有 *RedisManager 实例。
|
|
var RedisClient *redis.Client
|
|
|
|
// RedisManager Redis 连接管理器(#10)。照 database.Manager 模式:
|
|
// 实例化 + DefaultRedis 全局默认 + 包级 facade 代理,支持多实例与测试注入。
|
|
type RedisManager struct {
|
|
mu sync.Mutex
|
|
cfg *config.Config
|
|
client *redis.Client
|
|
}
|
|
|
|
// DefaultRedis 默认 Redis 管理器,包级 facade 代理到它。
|
|
var DefaultRedis = NewRedisManager()
|
|
|
|
// NewRedisManager 创建 Redis 管理器实例。
|
|
func NewRedisManager() *RedisManager { return &RedisManager{} }
|
|
|
|
// SetDefaultRedisManager 提升指定 RedisManager 为全局默认,后续包级 facade 走它。
|
|
// 用于多实例场景或测试注入 mock。
|
|
func SetDefaultRedisManager(m *RedisManager) {
|
|
if m != nil {
|
|
DefaultRedis = m
|
|
}
|
|
}
|
|
|
|
// Init 初始化 Redis 连接并 ping 验证。
|
|
func (m *RedisManager) Init(cfg *config.Config) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
client := redis.NewClient(&redis.Options{
|
|
Addr: cfg.Redis.Addr(),
|
|
Password: cfg.Redis.Password,
|
|
DB: cfg.Redis.DB,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
if err := client.Ping(ctx).Err(); err != nil {
|
|
client.Close()
|
|
return fmt.Errorf("Redis 连接失败: %w", err)
|
|
}
|
|
|
|
m.cfg = cfg
|
|
m.client = client
|
|
RedisClient = client // 同步兼容 facade
|
|
logger.Info("Redis 连接成功", zap.String("addr", cfg.Redis.Addr()))
|
|
return nil
|
|
}
|
|
|
|
// Close 关闭 Redis 连接。
|
|
func (m *RedisManager) Close() error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.client == nil {
|
|
return nil
|
|
}
|
|
err := m.client.Close()
|
|
m.client = nil
|
|
RedisClient = nil
|
|
return err
|
|
}
|
|
|
|
// Client 返回当前 Redis 客户端(未初始化返回 nil)。
|
|
func (m *RedisManager) Client() *redis.Client {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
return m.client
|
|
}
|
|
|
|
// HealthCheck Redis 健康检查。
|
|
func (m *RedisManager) HealthCheck(ctx context.Context) error {
|
|
m.mu.Lock()
|
|
client := m.client
|
|
m.mu.Unlock()
|
|
if client == nil {
|
|
return fmt.Errorf("Redis 未初始化")
|
|
}
|
|
return client.Ping(ctx).Err()
|
|
}
|
|
|
|
// --- 包级 facade(代理到 DefaultRedis,兼容存量) ---
|
|
|
|
// InitRedis 初始化 Redis 连接
|
|
func InitRedis(cfg *config.Config) error {
|
|
return DefaultRedis.Init(cfg)
|
|
}
|
|
|
|
// CloseRedis 关闭 Redis 连接
|
|
func CloseRedis() error {
|
|
return DefaultRedis.Close()
|
|
}
|
|
|
|
// HealthCheckRedis Redis 健康检查
|
|
func HealthCheckRedis(ctx context.Context) error {
|
|
return DefaultRedis.HealthCheck(ctx)
|
|
}
|
|
|
|
// GetRedis 获取 Redis 客户端
|
|
func GetRedis() *redis.Client {
|
|
return DefaultRedis.Client()
|
|
}
|