Skip to content

Commit 7caeb72

Browse files
Merge pull request #81 from jacobecox/main
Added redis connection retry
2 parents 730d451 + 7fd34b7 commit 7caeb72

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

examples/cpln-task-runner/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ Environment variables:
125125
| `REDIS_MASTER_NAME` | `mymaster` | Redis Sentinel master name |
126126
| `REDIS_PASSWORD` | `` | Redis authentication password |
127127
| `REDIS_SENTINEL_PASSWORD` | `` | Sentinel authentication password |
128+
| `REDIS_CONNECT_RETRIES` | `30` | Max retries for initial Redis connection |
129+
| `REDIS_RETRY_INTERVAL_SEC` | `2` | Seconds between connection retries |
128130
| `PORT` | `8080` | API server port |
129131
| `MODE` | `both` | Run mode: `api`, `worker`, or `both` |
130132
| `WORKER_CONCURRENCY` | `10` | Number of concurrent workers |

examples/cpln-task-runner/main.go

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,12 @@ var (
163163

164164
// --- Configuration ---
165165
var (
166-
RedisPassword = getEnv("REDIS_PASSWORD", "")
167-
RedisMasterName = getEnv("REDIS_MASTER_NAME", "mymaster")
168-
RedisSentinelAddr = getEnv("REDIS_SENTINEL_ADDR", "localhost:26379")
169-
RedisSentinelPass = getEnv("REDIS_SENTINEL_PASSWORD", "")
166+
RedisPassword = getEnv("REDIS_PASSWORD", "")
167+
RedisMasterName = getEnv("REDIS_MASTER_NAME", "mymaster")
168+
RedisSentinelAddr = getEnv("REDIS_SENTINEL_ADDR", "localhost:26379")
169+
RedisSentinelPass = getEnv("REDIS_SENTINEL_PASSWORD", "")
170+
RedisConnectRetries = getEnvInt("REDIS_CONNECT_RETRIES", 30) // Max retries for initial connection
171+
RedisRetryInterval = getEnvInt("REDIS_RETRY_INTERVAL_SEC", 2) // Seconds between retries
170172
Port = getEnv("PORT", "8080")
171173
AdminAPIKey = getEnv("ADMIN_API_KEY", "")
172174
Concurrency = getEnvInt("WORKER_CONCURRENCY", 10)
@@ -638,6 +640,44 @@ func initTracer(ctx context.Context) (func(context.Context) error, error) {
638640
return tp.Shutdown, nil
639641
}
640642

643+
// waitForRedis attempts to connect to Redis with retries
644+
// This handles the case where Redis Sentinel may not be ready when the app starts
645+
func waitForRedis(ctx context.Context, client *redis.Client) error {
646+
retryInterval := time.Duration(RedisRetryInterval) * time.Second
647+
648+
for attempt := 1; attempt <= RedisConnectRetries; attempt++ {
649+
err := client.Ping(ctx).Err()
650+
if err == nil {
651+
if attempt > 1 {
652+
slog.Info("Redis connection established", "attempt", attempt)
653+
}
654+
return nil
655+
}
656+
657+
if attempt == RedisConnectRetries {
658+
return fmt.Errorf("failed after %d attempts: %w", attempt, err)
659+
}
660+
661+
slog.Warn("Redis not ready, retrying...",
662+
"attempt", attempt,
663+
"max_attempts", RedisConnectRetries,
664+
"retry_in_seconds", RedisRetryInterval,
665+
"master", RedisMasterName,
666+
"sentinel", RedisSentinelAddr,
667+
"error", err,
668+
)
669+
670+
select {
671+
case <-ctx.Done():
672+
return ctx.Err()
673+
case <-time.After(retryInterval):
674+
// Continue to next attempt
675+
}
676+
}
677+
678+
return fmt.Errorf("max retries exceeded")
679+
}
680+
641681
func main() {
642682
initLogger()
643683

@@ -682,9 +722,9 @@ func main() {
682722
})
683723
defer redisClient.Close()
684724

685-
// Verify Redis connection
686-
if err := redisClient.Ping(ctx).Err(); err != nil {
687-
slog.Error("Failed to connect to Redis via Sentinel", "master", RedisMasterName, "sentinel", RedisSentinelAddr, "error", err)
725+
// Verify Redis connection with retries
726+
if err := waitForRedis(ctx, redisClient); err != nil {
727+
slog.Error("Failed to connect to Redis via Sentinel after retries", "master", RedisMasterName, "sentinel", RedisSentinelAddr, "error", err)
688728
os.Exit(1)
689729
}
690730
slog.Info("Connected to Redis via Sentinel", "master", RedisMasterName, "sentinel", RedisSentinelAddr)

0 commit comments

Comments
 (0)