Skip to content

Comments

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

Draft
mayankkapoor wants to merge 1 commit intoredis:masterfrom
mayankkapoor:fix/3127-client-doesnt-reconnect
Draft

[#3127] Fix for Redis Sentinel client doesn't reconnect after connection failure#3184
mayankkapoor wants to merge 1 commit intoredis:masterfrom
mayankkapoor:fix/3127-client-doesnt-reconnect

Conversation

@mayankkapoor
Copy link

@mayankkapoor mayankkapoor commented Feb 24, 2026

When a Redis Sentinel goes down and comes back up, the node-redis client fails to reconnect, throwing "None of the sentinels are available". This is likely a regression introduced in v5.9.0 (commit 73413e086c — "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.

  • 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

Description

Describe your pull request here


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)?

…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
Copy link

jit-ci bot commented Feb 24, 2026

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
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