From 9d125ba9bd96a1f0c1441ea0d54ca4069ef36055 Mon Sep 17 00:00:00 2001 From: TrapStoner Date: Fri, 29 May 2026 02:58:46 +0300 Subject: [PATCH] fix(redis): retry with exponential backoff on startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rueidis.NewClient pings Redis immediately; if the container starts before Redis is ready the backend fatals. Retry up to 10 times with exponential backoff (300ms → 810ms → 2.2s → … capped at 15s). --- pkg/utils/redis.go | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/pkg/utils/redis.go b/pkg/utils/redis.go index e38fb86..71b1753 100644 --- a/pkg/utils/redis.go +++ b/pkg/utils/redis.go @@ -1,22 +1,52 @@ package utils import ( + "fmt" + "log/slog" + "math" + "time" "github.com/redis/rueidis" ) var rdb rueidis.Client +const ( + redisMaxRetries = 10 + redisBaseDelay = 300 * time.Millisecond + redisBackoffFactor = 2.7 + redisMaxDelay = 15 * time.Second +) + func InitRedis() error { opt, err := rueidis.ParseURL(GetEnv("redis.url")) if err != nil { - return err + return fmt.Errorf("invalid redis url: %w", err) } - client, err := rueidis.NewClient(opt) - if err != nil { - return err + + var lastErr error + for attempt := range redisMaxRetries { + var client rueidis.Client + client, lastErr = rueidis.NewClient(opt) + if lastErr == nil { + rdb = client + return nil + } + if attempt == redisMaxRetries-1 { + break + } + delay := time.Duration(math.Min( + float64(redisBaseDelay)*math.Pow(redisBackoffFactor, float64(attempt)), + float64(redisMaxDelay), + )) + slog.Warn("redis connection failed, retrying", + "attempt", attempt+1, + "maxRetries", redisMaxRetries, + "retryIn", delay.String(), + "error", lastErr, + ) + time.Sleep(delay) } - rdb = client - return nil + return fmt.Errorf("redis connection failed after %d attempts: %w", redisMaxRetries, lastErr) } func GetRedisClient() rueidis.Client {