package config import ( "context" "fmt" "strings" "github.com/redis/go-redis/v9" "go.uber.org/zap" ) // initRedis initialise la connexion Redis. v1.0.9 Day 11 : when // `sentinelAddrs` is non-empty, we wire a Sentinel-aware FailoverClient // instead of a direct connection. The URL is still consulted for // password + DB index — Sentinel discovers the host:port pair. func initRedis(redisURL string, sentinelAddrs []string, sentinelMasterName, sentinelPassword string, logger *zap.Logger) (*redis.Client, error) { opts, err := redis.ParseURL(redisURL) if err != nil { return nil, err } // Configurer un logger filtré pour Redis pour éviter les warnings "maint_notifications" redis.SetLogger(&filteredRedisLogger{logger: logger}) var client *redis.Client if len(sentinelAddrs) > 0 { // FailoverClient : Sentinel discovers the current master and // transparently re-resolves on failover. `MasterName` MUST match // the value in sentinel.conf (`monitor `). client = redis.NewFailoverClient(&redis.FailoverOptions{ MasterName: sentinelMasterName, SentinelAddrs: sentinelAddrs, SentinelPassword: sentinelPassword, // Auth + db reused from the parsed URL so dev/prod stay parametric. Password: opts.Password, DB: opts.DB, // TLS cherrypicked from the URL (rediss://). TLSConfig: opts.TLSConfig, }) logger.Info("Redis Sentinel HA wired", zap.Strings("sentinels", sentinelAddrs), zap.String("master", sentinelMasterName)) } else { client = redis.NewClient(opts) } // Test de connexion ctx := context.Background() _, err = client.Ping(ctx).Result() if err != nil { return nil, err } return client, nil } // parseRedisSentinelAddrs splits the comma-separated REDIS_SENTINEL_ADDRS // env into a clean slice. Empty input -> nil (initRedis falls back to // single-instance). Trims whitespace + drops empty entries so a typo // like "a, ,b" doesn't dial a phantom sentinel. func parseRedisSentinelAddrs(raw string) []string { if raw == "" { return nil } parts := strings.Split(raw, ",") out := make([]string, 0, len(parts)) for _, p := range parts { p = strings.TrimSpace(p) if p != "" { out = append(out, p) } } if len(out) == 0 { return nil } return out } // filteredRedisLogger est un wrapper pour filtrer les logs de Redis type filteredRedisLogger struct { logger *zap.Logger } func (l *filteredRedisLogger) Printf(ctx context.Context, format string, v ...interface{}) { msg := fmt.Sprintf(format, v...) if strings.Contains(msg, "maint_notifications") { return // Ignorer ce warning spécifique en mode auto-discovery } l.logger.Debug("Redis internal", zap.String("message", msg)) }