Skip to content

Enhance Redis client to support Sentinel high availability#4559

Open
dyunwei wants to merge 2 commits intoQuantumNous:mainfrom
dyunwei:main
Open

Enhance Redis client to support Sentinel high availability#4559
dyunwei wants to merge 2 commits intoQuantumNous:mainfrom
dyunwei:main

Conversation

@dyunwei
Copy link
Copy Markdown

@dyunwei dyunwei commented Apr 30, 2026

Previously, InitRedisClient lacked support for Redis Sentinel. This update allows the application to connect to a Sentinel cluster for automatic failover.

Configuration is driven by the following new environment variables:

  • REDIS_SENTINEL_ADDRS (e.g., "192.168.1.10:26379,192.168.1.20:26379...")
  • REDIS_MASTER_NAME (e.g., "mymaster")
  • REDIS_PASSWORD
  • REDIS_SENTINEL_USERNAME (Optional)
  • REDIS_SENTINEL_PASSWORD (Optional)

⚠️ 提交说明 / PR Notice

📝 变更描述 / Description

官方文档 中描述了支持Redis的哨兵模式,但经过检查后,实际代码中并没支持。本次修改了common/redis.go 文件中 InitRedisClient 函数,目的就是为了支持该项功能。改动由copilot辅助完成,且由人工进行了review,并进行了集群测试。以下为该功能的新增的环境变量配置说明,后续会更新进入文档。

# 哨兵的地址,这里假设有3个哨兵
export REDIS_SENTINEL_ADDRS="192.168.1.10:26379,192.168.1.20:26379,192.168.1.30:26379"
# 哨兵模式下的主节点名称
export REDIS_MASTER_NAME="mymaster"
# Redis 数据库的密码
export REDIS_PASSWORD="MyStrongPassword123"
# 可选,哨兵认证时的用户名(如果设置免认证,则不用设置)
export REDIS_SENTINEL_USERNAME="sentinel_user" (optional)
# 可选,哨兵认证时的密码(如果设置免认证,则不用设置)
export REDIS_SENTINEL_PASSWORD="sentinel_pass" (optional)

🚀 变更类型 / Type of change

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

  • 实际运行的测试日志,结果表明redis集群连接测试通过
image
  • copliot自动化测试的日志,所有测试用例均通过
  • image

Summary by CodeRabbit

  • New Features

    • Added Redis Sentinel (high-availability) support and failover-capable client initialization
    • Client now initializes conditionally based on environment configuration
  • Improvements

    • Improved connection initialization and configuration handling
    • Reduced verbose debug output, replaced with a concise successful-connection message

Previously, `InitRedisClient` lacked support for Redis Sentinel. This update allows the application to connect to a Sentinel cluster for automatic failover.

Configuration is driven by the following new environment variables:
* REDIS_SENTINEL_ADDRS (e.g., "192.168.1.10:26379,192.168.1.20:26379...")
* REDIS_MASTER_NAME (e.g., "mymaster")
* REDIS_PASSWORD
* REDIS_SENTINEL_USERNAME (Optional)
* REDIS_SENTINEL_PASSWORD (Optional)
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Walkthrough

The InitRedisClient function now enables Redis when either REDIS_CONN_STRING or REDIS_SENTINEL_ADDRS is present, adding Redis Sentinel (failover) initialization when REDIS_SENTINEL_ADDRS is set and falling back to standalone client otherwise. Pool sizing, auth, DB selection, and a ping check are applied; logging was simplified.

Changes

Cohort / File(s) Summary
Redis initialization
common/redis.go
Added conditional enabling of Redis based on REDIS_CONN_STRING or REDIS_SENTINEL_ADDRS. Implemented Sentinel/failover client when REDIS_SENTINEL_ADDRS is provided (parses comma-separated sentinel endpoints, REDIS_MASTER_NAME, optional sentinel auth, plus REDIS_PASSWORD, REDIS_DB, REDIS_POOL_SIZE). Otherwise creates standalone client from REDIS_CONN_STRING. Added ping test and replaced detailed address/debug logs with a generic success message.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Init as InitRedisClient
    participant Env as Environment
    participant Sentinel as Redis Sentinel
    participant Redis as Redis Instance

    App->>Init: Call InitRedisClient()
    Init->>Env: Read REDIS_SENTINEL_ADDRS / REDIS_CONN_STRING
    alt Sentinel mode (REDIS_SENTINEL_ADDRS present)
        Env-->>Init: sentinel addrs, master name, creds
        Init->>Sentinel: Create failover client (pool, auth, DB)
        Sentinel->>Redis: Discover master endpoint
        Init->>Redis: Ping
        Redis-->>Init: Pong
    else Standalone mode
        Env-->>Init: connection string, creds
        Init->>Redis: Create standalone client (pool, auth, DB)
        Init->>Redis: Ping
        Redis-->>Init: Pong
    end
    Init-->>App: Redis client ready
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I parsed the seeds of sentinel strings tonight,
Split endpoints by commas, set auth just right,
Failover hops or single-line grace,
Redis wakes ready—steady my pace. 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enhance Redis client to support Sentinel high availability' accurately and specifically describes the main change: adding Redis Sentinel support to the Redis client implementation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@common/redis.go`:
- Around line 26-29: InitRedisClient currently only flips RedisEnabled=false
when env vars are missing, which can leak a previous RDB client and never reset
the flag on subsequent successful inits; update InitRedisClient to reset globals
at start (set RedisEnabled=false and RDB=nil), then only set RedisEnabled=true
after successfully creating and assigning the new Redis client (RDB), and ensure
any failure path also clears RDB (nil) so no previous client leaks; reference
symbols: InitRedisClient, RedisEnabled, RDB.
- Around line 66-82: The Sentinel (failover) branch builds
redis.NewFailoverClient without setting the DB index, so deployments using a
non-zero Redis DB silently connect to DB 0; update the FailoverOptions passed to
redis.NewFailoverClient to include the same DB index used in the standalone path
(set the DB field). To do this, extract the DB index the standalone path gets
(e.g., by calling redis.ParseURL(connString) or reading the existing DB
variable) and add DB: <thatIndex> to the redis.FailoverOptions passed to
redis.NewFailoverClient (symbols to change: redis.NewFailoverClient,
redis.FailoverOptions, MasterName, SentinelAddrs, SentinelUsername,
SentinelPassword, Password, PoolSize, add DB).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3f0c35d6-d1af-4b7a-880c-a6061885a5dd

📥 Commits

Reviewing files that changed from the base of the PR and between d2b30df and 6316b05.

📒 Files selected for processing (1)
  • common/redis.go

Comment thread common/redis.go
Comment thread common/redis.go
增加一个 REDIS_DB 环境变量,为哨兵模式指定 DB 索引。

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
common/redis.go (1)

26-29: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reset and republish the Redis globals per init call.

This still leaves RedisEnabled/RDB carrying state across repeated InitRedisClient calls: after one disabled init, a later successful init never flips RedisEnabled back to true, and disabling Redis later can keep an old client reachable through RDB. Reset the globals up front and only assign the new client after Ping succeeds.

Suggested fix
 func InitRedisClient() (err error) {
+	RedisEnabled = false
+	RDB = nil
+
 	if os.Getenv("REDIS_CONN_STRING") == "" && os.Getenv("REDIS_SENTINEL_ADDRS") == "" {
-		RedisEnabled = false
 		SysLog("REDIS_CONN_STRING and REDIS_SENTINEL_ADDRS not set, Redis is not enabled")
 		return nil
 	}
@@
-	if sentinelAddrs != "" {
+	var client *redis.Client
+	if sentinelAddrs != "" {
@@
-		RDB = redis.NewFailoverClient(&redis.FailoverOptions{
+		client = redis.NewFailoverClient(&redis.FailoverOptions{
 			MasterName:       masterName,
 			SentinelAddrs:    addrs,
 			SentinelUsername: sentinelUsername,
 			SentinelPassword: sentinelPassword,
 			Password:         password,
 			DB:               db,
 			PoolSize:         poolSize,
 		})
 	} else {
@@
-		RDB = redis.NewClient(opt)
+		client = redis.NewClient(opt)
 	}
@@
-	_, err = RDB.Ping(ctx).Result()
+	_, err = client.Ping(ctx).Result()
 	if err != nil {
 		FatalLog("Redis ping test failed: " + err.Error())
 	}
+	RDB = client
+	RedisEnabled = true
 
 	SysLog("Redis connection test passed")
 	return err
 }

Also applies to: 67-84, 90-95

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@common/redis.go` around lines 26 - 29, In InitRedisClient reset RedisEnabled
= false and RDB = nil at the start to clear prior state, then attempt to create
the new client (from connection-string or sentinel code paths) but do not assign
it to the global RDB or set RedisEnabled until after client.Ping(ctx) succeeds;
if Ping succeeds, close any previous client (if non-nil), set RDB to the new
client and RedisEnabled = true, and if Ping fails ensure the new client is
closed and globals remain disabled; update all branches (the direct conn-string
and sentinel branches used in InitRedisClient and the other similar blocks) to
follow this pattern and emit SysLog messages accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@common/redis.go`:
- Around line 26-29: In InitRedisClient reset RedisEnabled = false and RDB = nil
at the start to clear prior state, then attempt to create the new client (from
connection-string or sentinel code paths) but do not assign it to the global RDB
or set RedisEnabled until after client.Ping(ctx) succeeds; if Ping succeeds,
close any previous client (if non-nil), set RDB to the new client and
RedisEnabled = true, and if Ping fails ensure the new client is closed and
globals remain disabled; update all branches (the direct conn-string and
sentinel branches used in InitRedisClient and the other similar blocks) to
follow this pattern and emit SysLog messages accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ad943d16-7e39-4aa1-8320-77b7b518fb74

📥 Commits

Reviewing files that changed from the base of the PR and between 6316b05 and b44f0a2.

📒 Files selected for processing (1)
  • common/redis.go

@dyunwei dyunwei closed this Apr 30, 2026
@dyunwei dyunwei reopened this Apr 30, 2026
@dyunwei
Copy link
Copy Markdown
Author

dyunwei commented Apr 30, 2026

虽然接受了coderabbitai新增指定数据库索引的提议,但强烈建议只用 DB 0(即不要配置环境变量 REDIS_DB )。此外,基于最小修改原则,本次更新并没有修改以下变量的声明。

var RDB *redis.Client 
var RedisEnabled = true

沿用了已有版本关于是否启用Redis的逻辑:

if os.Getenv("REDIS_CONN_STRING") == "" && os.Getenv("REDIS_SENTINEL_ADDRS") == "" {
  RedisEnabled = false
  SysLog("REDIS_CONN_STRING and REDIS_SENTINEL_ADDRS not set, Redis is not enabled")
  return nil
}

@dyunwei
Copy link
Copy Markdown
Author

dyunwei commented Apr 30, 2026

@Calcium-Ion 麻烦抽空review一下,第一次在这个项目提交代码,不清楚流程对不对。。。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant