You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
2.0 KiB
98 lines
2.0 KiB
1 month ago
|
package database
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"gofaster/internal/shared/config"
|
||
|
"time"
|
||
|
|
||
|
"github.com/go-redis/redis/v8"
|
||
|
"go.uber.org/zap"
|
||
|
)
|
||
|
|
||
|
type RedisClient struct {
|
||
|
client *redis.Client
|
||
|
logger *zap.Logger
|
||
|
}
|
||
|
|
||
|
func NewRedisClient(cfg *config.RedisConfig, logger *zap.Logger) *RedisClient {
|
||
|
if logger == nil {
|
||
|
logger = zap.L()
|
||
|
}
|
||
|
|
||
|
// 记录连接参数(隐藏密码)
|
||
|
logger.Info("Initializing Redis client",
|
||
|
zap.String("host", cfg.Host),
|
||
|
zap.String("port", cfg.Port),
|
||
|
zap.Int("db", cfg.DB),
|
||
|
zap.Bool("has_password", cfg.Password != ""),
|
||
|
)
|
||
|
|
||
|
client := redis.NewClient(&redis.Options{
|
||
|
Addr: cfg.Host + ":" + cfg.Port,
|
||
|
Password: cfg.Password,
|
||
|
DB: cfg.DB,
|
||
|
})
|
||
|
|
||
|
// 测试连接(带超时和重试)
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
retries := 3
|
||
|
var lastErr error
|
||
|
for i := 0; i < retries; i++ {
|
||
|
if _, err := client.Ping(ctx).Result(); err != nil {
|
||
|
lastErr = err
|
||
|
logger.Warn("Redis connection attempt failed",
|
||
|
zap.Int("attempt", i+1),
|
||
|
zap.Error(err),
|
||
|
)
|
||
|
time.Sleep(1 * time.Second) // 延迟重试
|
||
|
continue
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
|
||
|
if lastErr != nil {
|
||
|
logger.Fatal("Failed to connect to Redis after retries",
|
||
|
zap.Int("retries", retries),
|
||
|
zap.Error(lastErr),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// 监控连接状态
|
||
|
go monitorConnection(client, logger)
|
||
|
|
||
|
logger.Info("Redis client initialized successfully")
|
||
|
return &RedisClient{
|
||
|
client: client,
|
||
|
logger: logger,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 监控 Redis 连接状态
|
||
|
func monitorConnection(client *redis.Client, logger *zap.Logger) {
|
||
|
ticker := time.NewTicker(30 * time.Second)
|
||
|
defer ticker.Stop()
|
||
|
|
||
|
for range ticker.C {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||
|
_, err := client.Ping(ctx).Result()
|
||
|
cancel()
|
||
|
|
||
|
if err != nil {
|
||
|
logger.Error("Redis connection health check failed",
|
||
|
zap.Error(err),
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *RedisClient) GetClient() *redis.Client {
|
||
|
return r.client
|
||
|
}
|
||
|
|
||
|
func (r *RedisClient) Close() error {
|
||
|
r.logger.Info("Closing Redis connection")
|
||
|
return r.client.Close()
|
||
|
}
|