Skip to content

Feature: Redis Sentinel and Cluster mode support #1021

@tonghs

Description

@tonghs

Problem

Background

The Redis plugin only supports single-node connections today. RedisPluginConnection.swift:196 calls redisConnectWithTimeout(host, Int32(port), …) with a single endpoint, and docs/databases/redis.mdx:102 notes "Cluster mode unsupported". Sentinel is similarly absent.

In production, Redis is rarely a single node. Sentinel-based HA and Cluster sharding are the two standard topologies, and users running either of them currently can't connect TablePro to their cluster, only to one underlying node, with no failover or routing awareness.

Current behavior on a non-single-node deployment

  • Pointing the form at a Sentinel port (26379): connection appears to succeed, but every data command fails because Sentinels only accept the SENTINEL command set. Confusing error messages.
  • Pointing the form at one Cluster master: connection succeeds, but reads/writes for any key whose slot belongs to a different master fail with MOVED <slot> <host:port>. The driver doesn't follow the redirect, so the user sees raw Redis errors with no guidance.

Both failure modes look like bugs rather than missing features.

Proposed solution

Scope (recommended phasing)

These have very different complexity. Sentinel is mostly a connect-time concern; Cluster touches every command path and the key tree UI. Suggest landing as two PRs:

Phase 1: Sentinel mode

  • Connection form: list of Sentinel nodes (host:port, repeatable), master name, optional Sentinel auth (separate from data-plane auth, since Redis 6.2+ supports SENTINEL AUTH).
  • Resolution: before opening the data connection, query each reachable Sentinel with SENTINEL get-master-addr-by-name <master> until one succeeds, then connect to the resolved master through the existing path.
  • Failover: on a dropped connection or READONLY error, re-query Sentinels and reconnect. Cache the last-known address but always re-resolve on failure.
  • Optional read-from-replica: SENTINEL replicas <master> for read scaling. Probably out of scope for the first iteration.

Phase 2: Cluster mode

  • Connection form: list of seed nodes (host:port, repeatable). Same auth fields as single-node.
  • Topology discovery: on connect, run CLUSTER SLOTS (or CLUSTER SHARDS on Redis 7+) to learn the slot-to-node map. Refresh on MOVED redirects and on a configurable interval.
  • Per-command routing: compute CRC16 slot for the key, route to the owning master. Honor MOVED (refresh and retry) and ASK (one-shot redirect with ASKING prefix).
  • Cross-slot operations: KEYS, SCAN, DBSIZE, INFO, FLUSHDB, etc. need to fan out across all masters and aggregate. The current sidebar key tree assumes one keyspace, which doesn't hold across shards.
  • Multi-key commands: MGET, DEL of multiple keys, transactions, and Lua scripts that touch multiple slots will need slot-grouping (multi-pass) or just surfacing the cluster error to the user.

Implementation note: hiredis doesn't ship cluster support

The plugin uses hiredis via Plugins/RedisDriverPlugin/CRedis/. Hiredis itself is single-connection only. Two realistic paths:

  1. Build slot routing in Swift on top of hiredis, holding one redisContext per master and dispatching by slot. More code, but the plugin already has the C bridge wired up.
  2. Vendor a separate cluster-aware C library like hiredis-cluster. Smaller code surface here but adds another .a to Libs/ and another C bridge module.

Sentinel can be implemented purely on top of the existing hiredis without either change, since it's just a different connect-time discovery step.

Affected files

  • Plugins/RedisDriverPlugin/RedisPluginConnection.swift — connect / reconnect.
  • Plugins/RedisDriverPlugin/RedisPluginDriver.swift — per-command routing for cluster.
  • Plugins/RedisDriverPlugin/RedisPlugin.swift — connection schema (mode picker, sentinel/seed node lists).
  • Plugins/RedisDriverPlugin/RedisCommandParser.swift — may need awareness of which commands are cluster-shardable.
  • docs/databases/redis.mdx — drop the "Cluster mode unsupported" note, document setup.
  • CHANGELOG.md — entry under [Unreleased].

Alternatives considered

Open questions

  1. Connection mode picker: extend the existing connection form with a "Mode" segmented control (Single / Sentinel / Cluster), or add Sentinel/Cluster as separate DatabaseType entries in the picker? The first preserves one Redis driver entry; the second matches how some clients expose them.
  2. Key tree under Cluster: aggregate keys from all shards into a single tree (matching the current single-keyspace UX), or show shards as top-level nodes? Aggregation matches user intuition but multiplies SCAN cost.
  3. Hiredis vs hiredis-cluster: option (1) or (2) above. Probably the maintainer's call based on long-term plugin maintenance preferences.
  4. Auth model: do we assume the same password works across all nodes (typical), or expose per-node auth?

Happy to send a draft PR for Phase 1 (Sentinel) once direction is confirmed.

Related database type

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions