Skip to content

feat(redis): add Redis Cluster client support to plugin-daemon#701

Draft
lin-snow wants to merge 4 commits intomainfrom
feat/redis-cluster-support
Draft

feat(redis): add Redis Cluster client support to plugin-daemon#701
lin-snow wants to merge 4 commits intomainfrom
feat/redis-cluster-support

Conversation

@lin-snow
Copy link
Copy Markdown

@lin-snow lin-snow commented Apr 18, 2026

Description

背景

目前 plugin-daemon 的 Redis 初始化只支持 单机 (Single)哨兵 (Sentinel) 两种模式。在使用 Redis Cluster 部署的环境中,用户无法直接接入,需要额外的代理或降级方案。本 PR 补齐 Cluster 模式,让三种拓扑在部署侧完全对齐。

变更内容

  • 新增集群初始化入口 pkg/utils/cache/redis.go

    • 新增 InitRedisClusterClient(addrs, username, password, useSsl, tlsConf),基于 redis.NewClusterClient 构建,与现有 Single / Sentinel 路径共享同一个 redis.UniversalClient 抽象,下游无感知。
    • 延续既有 redisotel tracing 注入与 Ping 健康检查。
    • addrs 为空的情况返回显式错误,避免配置遗漏时静默失败。
  • 新增配置项 internal/types/app/config.go

    • REDIS_USE_CLUSTERS (bool, 默认 false):Cluster 模式总开关。
    • REDIS_CLUSTERS (string):以英文逗号分隔的 host:port 列表。
    • REDIS_CLUSTERS_PASSWORD (string, 可选):Cluster 专用密码;未设置时回退到 REDIS_PASSWORD,方便复用既有凭据。
  • 接入启动流程 internal/core/plugin_manager/manager.go

    • PluginManager.Launch 的 Redis 初始化加入 Cluster 分支,优先级:ClustersSentinelSingle
    • 抽出 splitAndTrimCSV 小工具对 REDIS_CLUSTERS 做切分与空值/空白过滤,容忍 "a, b, ,c" 这类不规整配置。

兼容性

  • 默认 REDIS_USE_CLUSTERS=false,所有现有部署零改动、零行为变化。
  • Sentinel 与 Single 模式的代码路径未做修改,无回归风险。
  • 配置项全部走环境变量,与仓内既有风格一致。

使用方式

REDIS_USE_CLUSTERS=true
REDIS_CLUSTERS=redis-0.example:6379,redis-1.example:6379,redis-2.example:6379
REDIS_CLUSTERS_PASSWORD=<optional,不填则复用 REDIS_PASSWORD>

测试计划

  • 单机 Redis 模式启动正常(回归)
  • Sentinel 模式启动正常(回归)
  • Cluster 模式连通真实集群,插件安装 / 调用 / 缓存读写链路正常
  • REDIS_USE_CLUSTERS=true 但 REDIS_CLUSTERS 为空时启动报错清晰
  • 开启 TLS (REDIS_USE_SSL=true) 时 Cluster 握手正常

Wire the missing third branch so operators can point the daemon at a
Redis Cluster without falling back to dialing an empty REDIS_HOST:PORT
and panicking at startup.

* introduce REDIS_USE_CLUSTERS / REDIS_CLUSTERS /
  REDIS_CLUSTERS_PASSWORD envs, aligned with dify api naming so Helm
  can set a single env group
* branch in PluginManager.Launch for Cluster ahead of the existing
  Sentinel / standalone paths; falls back to REDIS_PASSWORD if the
  cluster-specific password is not set
* implement cache.InitRedisClusterClient via redis.NewClusterClient;
  downstream cache / lock / pub-sub helpers keep working because
  `client` is declared as redis.UniversalClient

Redis Cluster disables SELECT DB, so the cluster branch does not
plumb RedisDB. This is intentional and documented in the release
note accompanying the overall Redis Cluster support work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lin-snow lin-snow self-assigned this Apr 18, 2026
@lin-snow lin-snow added the enhancement New feature or request label Apr 18, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds Redis Cluster support, including new configuration fields and the InitRedisClusterClient utility. The PluginManager now supports cluster initialization. Key feedback highlights that the current Transaction() implementation is incompatible with Redis Cluster, suggests generalizing error messages in utility functions, and recommends refactoring redundant TLS configuration logic.

Comment thread pkg/utils/cache/redis.go Outdated
Comment thread pkg/utils/cache/redis.go Outdated
Comment thread pkg/utils/cache/redis.go Outdated
Comment on lines +119 to +127
if useSsl {
if tlsConf != nil {
opts.TLSConfig = tlsConf
} else {
opts.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

此处的 TLS 配置逻辑与 InitRedisClient (通过 getRedisOptions) 和 InitRedisSentinelClient 中的逻辑完全重复。建议将这部分逻辑提取为一个通用的辅助函数,以提高代码的可维护性并减少重复。

lin-snow and others added 3 commits April 20, 2026 11:36
Narrow the plugin-daemon Redis client to standalone and sentinel modes;
remove the cluster code paths that were briefly exercised on this branch.

Changes:
- Remove REDIS_USE_CLUSTERS / REDIS_CLUSTERS / REDIS_CLUSTERS_PASSWORD
  env fields from app.Config.
- Remove the cluster branch (plus the two cluster-specific fail-fast
  guards on REDIS_USE_CLUSTERS + REDIS_USE_SENTINEL and REDIS_DB != 0)
  from PluginManager.Launch. The init block is now just sentinel or
  standalone.
- Delete cache.InitRedisClusterClient. The main redis client + all
  helpers (Transaction, pub/sub, lock, etc.) already route through
  redis.UniversalClient so downstream code needs no adjustment.

Intentionally kept:
- Transaction(fn, watchKeys...) signature: the variadic signature is
  backwards-compatible with every existing Transaction(fn) call and the
  one new-style caller (debugging_service) benefits from real WATCH
  semantics even on standalone — this is correctness-independent of
  cluster support.
- parser.SplitAndTrimCSV: the sentinel branch migrated to it in 617e7a5
  and still uses it to parse REDIS_SENTINELS, so the helper has a
  standalone/sentinel consumer and stays.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant