From c8c9126c357f9e271ed15034dca0faaecd4aeabd Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Sun, 28 Sep 2025 20:30:49 +0700 Subject: [PATCH 1/7] fix redis sentinel failover --- packages/client/lib/sentinel/index.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/client/lib/sentinel/index.ts b/packages/client/lib/sentinel/index.ts index 63c4586293..a148241079 100644 --- a/packages/client/lib/sentinel/index.ts +++ b/packages/client/lib/sentinel/index.ts @@ -928,6 +928,16 @@ class RedisSentinelInternal< } } + #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(); + } + async close() { this.#destroy = true; @@ -1197,8 +1207,9 @@ class RedisSentinelInternal< error: err }; this.emit('client-error', event); - this.#reset(); - }); + this.#handleSentinelFailure(node); + }) + .on('end', () => this.#handleSentinelFailure(node)); this.#sentinelClient = client; this.#trace(`transform: adding sentinel client connect() to promise list`); From 2409c96a6c79ea3a4aabc20efcac440858b5b8c1 Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Sun, 21 Sep 2025 21:11:55 +0700 Subject: [PATCH 2/7] fix: resolve doubly linked list push issue --- packages/client/lib/client/linked-list.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/client/lib/client/linked-list.ts b/packages/client/lib/client/linked-list.ts index 461f1d4082..6d01cd1f5f 100644 --- a/packages/client/lib/client/linked-list.ts +++ b/packages/client/lib/client/linked-list.ts @@ -29,11 +29,16 @@ export class DoublyLinkedList { ++this.#length; if (this.#tail === undefined) { - return this.#tail = this.#head = { + this.#head = { + previous: undefined, + next: this.#tail, + value + } + return this.#tail = { previous: this.#head, next: undefined, value - }; + } } return this.#tail = this.#tail.next = { From 8b5e4f485a8782542cc6d490c582655e41ebbbd9 Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Sun, 21 Sep 2025 21:35:07 +0700 Subject: [PATCH 3/7] fix semicolon syntax --- packages/client/lib/client/linked-list.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/lib/client/linked-list.ts b/packages/client/lib/client/linked-list.ts index 6d01cd1f5f..bfeadd794f 100644 --- a/packages/client/lib/client/linked-list.ts +++ b/packages/client/lib/client/linked-list.ts @@ -33,12 +33,12 @@ export class DoublyLinkedList { previous: undefined, next: this.#tail, value - } + }; return this.#tail = { previous: this.#head, next: undefined, value - } + }; } return this.#tail = this.#tail.next = { From 441004f5f3cbf6e77a74e0489bb884cf2cb68dc6 Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Wed, 24 Sep 2025 22:56:08 +0700 Subject: [PATCH 4/7] correctly set the removed node ref --- packages/client/lib/client/linked-list.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/client/lib/client/linked-list.ts b/packages/client/lib/client/linked-list.ts index bfeadd794f..f587558488 100644 --- a/packages/client/lib/client/linked-list.ts +++ b/packages/client/lib/client/linked-list.ts @@ -29,13 +29,8 @@ export class DoublyLinkedList { ++this.#length; if (this.#tail === undefined) { - this.#head = { + return this.#head = this.#tail = { previous: undefined, - next: this.#tail, - value - }; - return this.#tail = { - previous: this.#head, next: undefined, value }; @@ -92,15 +87,18 @@ export class DoublyLinkedList { if (this.#tail === node) { this.#tail = node.previous; - } - + } if (this.#head === node) { this.#head = node.next; } else { - node.previous!.next = node.next; - node.previous = undefined; + if (node.previous) { + node.previous.next = node.next; + } } - + if (node.next) { + node.next.previous = node.previous; + } + node.previous = undefined; node.next = undefined; } From 9245b43c34b4e5c3aa467732db0e3b2eaaebdbff Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Thu, 25 Sep 2025 22:30:02 +0700 Subject: [PATCH 5/7] fix linked list node iterator --- packages/client/lib/client/linked-list.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/client/lib/client/linked-list.ts b/packages/client/lib/client/linked-list.ts index f587558488..9521a4ceb9 100644 --- a/packages/client/lib/client/linked-list.ts +++ b/packages/client/lib/client/linked-list.ts @@ -94,7 +94,7 @@ export class DoublyLinkedList { if (node.previous) { node.previous.next = node.next; } - } + } if (node.next) { node.next.previous = node.previous; } @@ -118,8 +118,9 @@ export class DoublyLinkedList { *nodes() { let node = this.#head; while(node) { + const next = node.next yield node; - node = node.next; + node = next; } } } From 234f1b6466bd83510a8ac94ddcad70dbcb2a3afe Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Fri, 26 Sep 2025 13:00:10 +0700 Subject: [PATCH 6/7] revert push logic and refactor remove logic --- packages/client/lib/client/linked-list.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/client/lib/client/linked-list.ts b/packages/client/lib/client/linked-list.ts index 9521a4ceb9..0cfd8cf2ea 100644 --- a/packages/client/lib/client/linked-list.ts +++ b/packages/client/lib/client/linked-list.ts @@ -30,7 +30,7 @@ export class DoublyLinkedList { if (this.#tail === undefined) { return this.#head = this.#tail = { - previous: undefined, + previous: this.#head, next: undefined, value }; @@ -73,7 +73,7 @@ export class DoublyLinkedList { --this.#length; const node = this.#head; if (node.next) { - node.next.previous = node.previous; + node.next.previous = undefined; this.#head = node.next; node.next = undefined; } else { @@ -92,11 +92,11 @@ export class DoublyLinkedList { this.#head = node.next; } else { if (node.previous) { - node.previous.next = node.next; + node.previous.next = node.next; + } + if (node.next) { + node.next.previous = node.previous; } - } - if (node.next) { - node.next.previous = node.previous; } node.previous = undefined; node.next = undefined; From 4eb46bb7e5bb2c2da1f0ae67d4b77f034b7599a3 Mon Sep 17 00:00:00 2001 From: Vuong Ngo Date: Wed, 1 Oct 2025 21:26:23 +0700 Subject: [PATCH 7/7] add linked list tests --- .../client/lib/client/linked-list.spec.ts | 34 ++++++++++++++++++- packages/client/lib/client/linked-list.ts | 1 + packages/client/lib/sentinel/index.ts | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/client/lib/client/linked-list.spec.ts b/packages/client/lib/client/linked-list.spec.ts index c791d21900..8837936405 100644 --- a/packages/client/lib/client/linked-list.spec.ts +++ b/packages/client/lib/client/linked-list.spec.ts @@ -6,7 +6,7 @@ import { import { equal, deepEqual } from "assert/strict"; describe("DoublyLinkedList", () => { - const list = new DoublyLinkedList(); + const list = new DoublyLinkedList(); it("should start empty", () => { equal(list.length, 0); @@ -96,6 +96,38 @@ describe("DoublyLinkedList", () => { } equal(count, 6); }); + + it("should handle remove on empty list", () => { + list.reset(); + const node = list.push(1); + list.remove(node); + equal(list.length, 0); + deepEqual(Array.from(list), []); + list.remove(node); + equal(list.length, 0); + deepEqual(Array.from(list), []); + }); + + + it("should safely remove nodes while iterating", () => { + list.reset(); + list.push(1); + list.push(2); + list.push(3); + list.push(4); + list.push(5); + + const visited: number[] = []; + for (const node of list.nodes()) { + visited.push(node.value); + if (node.value % 2 === 0) { + list.remove(node); + } + } + deepEqual(visited, [1, 2, 3, 4, 5]); + equal(list.length, 3); + deepEqual(Array.from(list), [1, 3, 5]); + }); }); describe("SinglyLinkedList", () => { diff --git a/packages/client/lib/client/linked-list.ts b/packages/client/lib/client/linked-list.ts index 0cfd8cf2ea..910319268a 100644 --- a/packages/client/lib/client/linked-list.ts +++ b/packages/client/lib/client/linked-list.ts @@ -83,6 +83,7 @@ export class DoublyLinkedList { } remove(node: DoublyLinkedNode) { + if (this.#length === 0) return; --this.#length; if (this.#tail === node) { diff --git a/packages/client/lib/sentinel/index.ts b/packages/client/lib/sentinel/index.ts index a148241079..a9a2b9a5e5 100644 --- a/packages/client/lib/sentinel/index.ts +++ b/packages/client/lib/sentinel/index.ts @@ -936,7 +936,7 @@ class RedisSentinelInternal< this.#sentinelRootNodes.splice(found, 1); } this.#reset(); - } + } async close() { this.#destroy = true;