Skip to content

[#3127] Fix for Redis Sentinel client doesn't reconnect after connection failure - #3184

Closed
mayankkapoor wants to merge 2 commits into
redis:masterfrom
mayankkapoor:fix/3127-client-doesnt-reconnect
Closed

mayankkapoor wants to merge 2 commits into
redis:masterfrom
mayankkapoor:fix/3127-client-doesnt-reconnect

Conversation

@mayankkapoor

@mayankkapoor mayankkapoor commented Feb 24, 2026

Copy link
Copy Markdown

Description

When a Redis Sentinel goes down and comes back up, the node-redis client fails to reconnect, throwing "None of the sentinels are available". It seems this is a regression introduced in v5.9.0 (commit 73413e0 — "fix: resolve doubly linked list push issue (#3085)").

Root Cause: #handleSentinelFailure() (added in v5.9.0) permanently removes the sentinel node from #sentinelRootNodes via splice() when its connection drops. When #reset() then calls observe(), the sentinel list is empty (or missing that node), so reconnection is impossible.

Secondary issue: The sentinel list update in transform() (line 1350) compares only array lengths (analyzed.sentinelList.length != this.#sentinelRootNodes.length), so even if reconnection succeeds via another sentinel, a removed node may never be restored if the list sizes happen to match.

Fix:

  1. Stop removing sentinels from #sentinelRootNodes in #handleSentinelFailure — just call #reset() so reconnection is retried against all known sentinels.
  2. Fix the sentinel list update check: the old code only compared array lengths, so it missed cases where the list contents changed but the length stayed the same. Replaced with a proper element-wise comparison (areSentinelListsEqual).

Fixes #3127

Checklist

  • Does npm test pass with this change (including linting)?
  • Is the new or changed code fully tested?
  • Is a documentation update included (if this change modifies existing APIs, or introduces new ones)? N/A no API changes, this is a bug fix for internal reconnection logic.

…ent fails to reconnect, throwing `"None of the sentinels are available"`. This is a regression introduced in v5.9.0 (commit `73413e086c` — "fix: resolve doubly linked list push issue (redis#3085)").

**Root Cause:** `#handleSentinelFailure()` (added in v5.9.0) permanently removes the sentinel node from `#sentinelRootNodes` via `splice()` when its connection drops. When `#reset()` then calls `observe()`, the sentinel list is empty (or missing that node), so reconnection is impossible.

**Secondary issue:** The sentinel list update in `transform()` (line 1350) compares only array lengths (`analyzed.sentinelList.length != this.#sentinelRootNodes.length`), so even if reconnection succeeds via another sentinel, a removed node may never be restored if the list sizes happen to match.

- [ ] **Task 1:** Fix `#handleSentinelFailure` — stop permanently removing sentinel nodes
  - **File:** `packages/client/lib/sentinel/index.ts` (lines 934–942)
  - Remove the `splice()` call. A transient TCP disconnect (which happens during sentinel restart) should not permanently delete the node from the root list. Just call `#reset()` to trigger reconnection, matching v5.8.3 behavior.
  - Before (broken):
    ```typescript
    #handleSentinelFailure(node: RedisNode) {
        const found = this.#sentinelRootNodes.findIndex(
            (rootNode) => rootNode.host === node.host && rootNode.port === node.port
        );
        if (found !== -1) {
            this.#sentinelRootNodes.splice(found, 1);
        }
        this.#reset();
    }
    ```
  - After (fixed):
    ```typescript
    #handleSentinelFailure(node: RedisNode) {
        this.#reset();
    }
    ```

- [ ] **Task 2:** Fix sentinel list update condition in `transform()`
  - **File:** `packages/client/lib/sentinel/index.ts` (line 1350)
  - Replace the length-only comparison with a proper content comparison so that nodes removed or added are always detected.
  - Before:
    ```typescript
    if (analyzed.sentinelList.length != this.#sentinelRootNodes.length) {
    ```
  - After — compare actual content:
    ```typescript
    if (!areSentinelListsEqual(analyzed.sentinelList, this.#sentinelRootNodes)) {
    ```
  - Add a helper (either inline or as a small private method) that compares host+port of each node, not just array length.

- [ ] **Task 3:** Run existing tests to confirm no regressions
  - Run `npm test` in the `packages/client` directory
  - Look for and run any sentinel-specific test files

- [ ] **Task 4:** Verify the fix scenario
  - Confirm `#sentinelRootNodes` retains the original sentinel entry after disconnect
  - Confirm `observe()` retries that sentinel and succeeds once it's back online
  - Confirm no `"None of the sentinels are available"` error after sentinel restart
@jit-ci

jit-ci Bot commented Feb 24, 2026

Copy link
Copy Markdown

Hi, I’m Jit, a friendly security platform designed to help developers build secure applications from day zero with an MVS (Minimal viable security) mindset.

In case there are security findings, they will be communicated to you as a comment inside the PR.

Hope you’ll enjoy using Jit.

Questions? Comments? Want to learn more? Get in touch with us.

@mayankkapoor mayankkapoor changed the title Fix for Redis Sentinel client doesn't reconnect after connection failure #3127 [#3127] Fix for Redis Sentinel client doesn't reconnect after connection failure Feb 24, 2026
@mayankkapoor
mayankkapoor marked this pull request as draft February 24, 2026 12:37
Exports areSentinelListsEqual and adds tests to prevent the regression
where sentinel nodes were removed from the root list on failure, and
where sentinel list changes were only detected by length, not content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mayankkapoor
mayankkapoor marked this pull request as ready for review February 24, 2026 13:50
@nkaradzhov

Copy link
Copy Markdown
Collaborator

@mayankkapoor thanks for the PR, I will have a look

@nkaradzhov

Copy link
Copy Markdown
Collaborator

@mayankkapoor I addressed both issues in a different PR with integration tests, so this one can be closed.

@nkaradzhov nkaradzhov closed this Mar 2, 2026
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.

Redis Sentinel client doesn't reconnect after connection failure

2 participants