From 334bfabcfe465e88f1b838885575f7b3c6785a02 Mon Sep 17 00:00:00 2001 From: uki00a Date: Thu, 10 Nov 2022 05:01:14 +0900 Subject: [PATCH 01/20] WIP: Auto-recconect --- tests/commands/general.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/commands/general.ts b/tests/commands/general.ts index cedce06c..b854544c 100644 --- a/tests/commands/general.ts +++ b/tests/commands/general.ts @@ -162,6 +162,26 @@ export function generalTests( }); }); + describe("auto-reconnection", () => { + it("reconnects when the connection is lost", async () => { + const client2 = await newClient(getOpts()); + try { + const id = await client2.clientID(); + await client.clientKill({ id }); + const reply = await client2.ping(); + assertEquals(reply, "OK"); + } finally { + client2.close(); + } + }); + + it("does not reconnect when the connection is manually closed by the user", async () => { + const client2 = await newClient(getOpts()); + client2.close(); + await assertRejects(() => client2.ping()); + }); + }); + describe("createLazyClient", () => { it("returns the lazily connected client", async () => { const opts = getOpts(); From 7e0eb8eb50fca7c88aac1175369f57e73f42136a Mon Sep 17 00:00:00 2001 From: uki00a Date: Thu, 10 Nov 2022 05:19:41 +0900 Subject: [PATCH 02/20] feat: implement auto-reconnection --- connection.ts | 26 ++++++++++++++++++++++++-- tests/commands/general.ts | 14 +++++++------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/connection.ts b/connection.ts index 7cad3e57..97e1b94d 100644 --- a/connection.ts +++ b/connection.ts @@ -108,8 +108,26 @@ export class RedisConnection implements Connection { command: string, ...args: Array ): Promise { - const reply = await sendCommand(this.writer, this.reader, command, ...args); - return reply.value(); + try { + const reply = await sendCommand( + this.writer, + this.reader, + command, + ...args, + ); + return reply.value(); + } catch (error) { + if (!(error instanceof Deno.errors.BadResource)) { + throw error; + } + + if (!this.isManuallyClosedByUser()) { + // Try to reconnect to the server and retry the command + this.close(); + await this.connect(); + return this.sendCommand(command, ...args); + } + } } /** @@ -183,6 +201,10 @@ export class RedisConnection implements Connection { await this.sendCommand("PING"); } } + + private isManuallyClosedByUser(): boolean { + return this._isClosed && !this._isConnected; + } } class AuthenticationError extends Error {} diff --git a/tests/commands/general.ts b/tests/commands/general.ts index b854544c..a045a9bf 100644 --- a/tests/commands/general.ts +++ b/tests/commands/general.ts @@ -164,21 +164,21 @@ export function generalTests( describe("auto-reconnection", () => { it("reconnects when the connection is lost", async () => { - const client2 = await newClient(getOpts()); + const tempClient = await newClient(getOpts()); try { - const id = await client2.clientID(); + const id = await tempClient.clientID(); await client.clientKill({ id }); - const reply = await client2.ping(); + const reply = await tempClient.ping(); assertEquals(reply, "OK"); } finally { - client2.close(); + tempClient.close(); } }); it("does not reconnect when the connection is manually closed by the user", async () => { - const client2 = await newClient(getOpts()); - client2.close(); - await assertRejects(() => client2.ping()); + const tempClient = await newClient(getOpts()); + tempClient.close(); + await assertRejects(() => tempClient.ping()); }); }); From af0c009b29f01c44f5d18e76ae3b735ecd2034f9 Mon Sep 17 00:00:00 2001 From: uki00a Date: Thu, 1 Dec 2022 06:49:38 +0900 Subject: [PATCH 03/20] fix: use `Connection#sendCommand` --- connection.ts | 16 +++++++++------- executor.ts | 7 +------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/connection.ts b/connection.ts index 97e1b94d..dc728eb0 100644 --- a/connection.ts +++ b/connection.ts @@ -21,6 +21,7 @@ export interface Connection { close(): void; connect(): Promise; reconnect(): Promise; + sendCommand(command: string, ...args: Array): Promise; } export interface RedisConnectionOptions { @@ -117,16 +118,17 @@ export class RedisConnection implements Connection { ); return reply.value(); } catch (error) { - if (!(error instanceof Deno.errors.BadResource)) { + if ( + !(error instanceof Deno.errors.BadResource) || + this.isManuallyClosedByUser() + ) { throw error; } - if (!this.isManuallyClosedByUser()) { - // Try to reconnect to the server and retry the command - this.close(); - await this.connect(); - return this.sendCommand(command, ...args); - } + // Try to reconnect to the server and retry the command + this.close(); + await this.connect(); + return this.sendCommand(command, ...args); } } diff --git a/executor.ts b/executor.ts index f9945499..5f6cfaf5 100644 --- a/executor.ts +++ b/executor.ts @@ -48,12 +48,7 @@ export class MuxExecutor implements CommandExecutor { private dequeue(): void { const [e] = this.queue; if (!e) return; - sendCommand( - this.connection.writer, - this.connection.reader, - e.command, - ...e.args, - ) + this.connection.sendCommand(e.command, ...e.args) .then(e.d.resolve) .catch(async (error) => { if ( From a95e9c504af46dffcc55758ceae1b39b821b01e4 Mon Sep 17 00:00:00 2001 From: uki00a Date: Fri, 2 Dec 2022 06:46:32 +0900 Subject: [PATCH 04/20] chore: make `sendCommand` public --- connection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connection.ts b/connection.ts index dc728eb0..bd46a2b6 100644 --- a/connection.ts +++ b/connection.ts @@ -105,7 +105,7 @@ export class RedisConnection implements Connection { await this.sendCommand("SELECT", db); } - private async sendCommand( + async sendCommand( command: string, ...args: Array ): Promise { From 0568f227fdc61bc2a5b51b6bd38b9ea97057db53 Mon Sep 17 00:00:00 2001 From: uki00a Date: Fri, 2 Dec 2022 06:49:45 +0900 Subject: [PATCH 05/20] fix: return type of `sendCommand` --- connection.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connection.ts b/connection.ts index bd46a2b6..b873da37 100644 --- a/connection.ts +++ b/connection.ts @@ -1,5 +1,5 @@ import { sendCommand } from "./protocol/mod.ts"; -import type { Raw, RedisValue } from "./protocol/mod.ts"; +import type { RedisReply, RedisValue } from "./protocol/mod.ts"; import type { Backoff } from "./backoff.ts"; import { exponentialBackoff } from "./backoff.ts"; import { ErrorReplyError } from "./errors.ts"; @@ -21,7 +21,7 @@ export interface Connection { close(): void; connect(): Promise; reconnect(): Promise; - sendCommand(command: string, ...args: Array): Promise; + sendCommand(command: string, ...args: Array): Promise; } export interface RedisConnectionOptions { @@ -116,7 +116,7 @@ export class RedisConnection implements Connection { command, ...args, ); - return reply.value(); + return reply; } catch (error) { if ( !(error instanceof Deno.errors.BadResource) || From 266646457fe74f14c72f27fe647290dce705db06 Mon Sep 17 00:00:00 2001 From: uki00a Date: Fri, 2 Dec 2022 06:52:36 +0900 Subject: [PATCH 06/20] fix: resolve type error --- connection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connection.ts b/connection.ts index b873da37..1b077b22 100644 --- a/connection.ts +++ b/connection.ts @@ -108,7 +108,7 @@ export class RedisConnection implements Connection { async sendCommand( command: string, ...args: Array - ): Promise { + ): Promise { try { const reply = await sendCommand( this.writer, From 356e9992544ee1eb7662813f29cd607618509d6c Mon Sep 17 00:00:00 2001 From: uki00a Date: Fri, 2 Dec 2022 06:56:38 +0900 Subject: [PATCH 07/20] chore: run linter --- executor.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/executor.ts b/executor.ts index 5f6cfaf5..d917706e 100644 --- a/executor.ts +++ b/executor.ts @@ -4,7 +4,6 @@ import { Deferred, deferred, } from "./vendor/https/deno.land/std/async/deferred.ts"; -import { sendCommand } from "./protocol/mod.ts"; import type { RedisReply, RedisValue } from "./protocol/mod.ts"; export interface CommandExecutor { From bad6736c2d0ef65e6e1437d7c5f56741651497f8 Mon Sep 17 00:00:00 2001 From: uki00a Date: Fri, 2 Dec 2022 07:07:05 +0900 Subject: [PATCH 08/20] fix: `sendCommand` signature --- connection.ts | 2 +- protocol/command.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/connection.ts b/connection.ts index 1b077b22..88c74dd5 100644 --- a/connection.ts +++ b/connection.ts @@ -114,7 +114,7 @@ export class RedisConnection implements Connection { this.writer, this.reader, command, - ...args, + args, ); return reply; } catch (error) { diff --git a/protocol/command.ts b/protocol/command.ts index 5dacf4c0..2d0a2533 100644 --- a/protocol/command.ts +++ b/protocol/command.ts @@ -91,7 +91,7 @@ export async function sendCommand( writer: BufWriter, reader: BufReader, command: string, - ...args: RedisValue[] + args: RedisValue[], ): Promise { await writeRequest(writer, command, args); await writer.flush(); From e36efe27276ec52335dfcac3353669388792b924 Mon Sep 17 00:00:00 2001 From: uki00a Date: Tue, 13 Dec 2022 06:37:22 +0900 Subject: [PATCH 09/20] chore: debug --- tests/commands/general.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/commands/general.ts b/tests/commands/general.ts index 33f34e6c..efe6cb2f 100644 --- a/tests/commands/general.ts +++ b/tests/commands/general.ts @@ -183,7 +183,7 @@ export function generalTests( }); }); - describe("auto-reconnection", () => { + describe("automatic reconnection", () => { it("reconnects when the connection is lost", async () => { const tempClient = await newClient(getOpts()); try { @@ -191,6 +191,7 @@ export function generalTests( await client.clientKill({ id }); const reply = await tempClient.ping(); assertEquals(reply, "OK"); + console.info("OK"); } finally { tempClient.close(); } @@ -200,6 +201,7 @@ export function generalTests( const tempClient = await newClient(getOpts()); tempClient.close(); await assertRejects(() => tempClient.ping()); + console.info("OK"); }); }); From 085dea82f8af35bfa8d6baa5c82abf0f423ef664 Mon Sep 17 00:00:00 2001 From: uki00a Date: Tue, 13 Dec 2022 06:43:31 +0900 Subject: [PATCH 10/20] fix: retry logic --- connection.ts | 20 ++++++++++++++++---- tests/commands/general.ts | 2 -- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/connection.ts b/connection.ts index 88c74dd5..5e425c67 100644 --- a/connection.ts +++ b/connection.ts @@ -125,10 +125,22 @@ export class RedisConnection implements Connection { throw error; } - // Try to reconnect to the server and retry the command - this.close(); - await this.connect(); - return this.sendCommand(command, ...args); + for (let i = 0; i < this.maxRetryCount; i++) { + // Try to reconnect to the server and retry the command + this.close(); + await this.connect(); + + const reply = await sendCommand( + this.writer, + this.reader, + command, + args, + ); + + return reply; + } + + throw error; } } diff --git a/tests/commands/general.ts b/tests/commands/general.ts index efe6cb2f..97501b62 100644 --- a/tests/commands/general.ts +++ b/tests/commands/general.ts @@ -191,7 +191,6 @@ export function generalTests( await client.clientKill({ id }); const reply = await tempClient.ping(); assertEquals(reply, "OK"); - console.info("OK"); } finally { tempClient.close(); } @@ -201,7 +200,6 @@ export function generalTests( const tempClient = await newClient(getOpts()); tempClient.close(); await assertRejects(() => tempClient.ping()); - console.info("OK"); }); }); From 43f0194cad3bc8479ff4fdf4a3638a585a6f1de2 Mon Sep 17 00:00:00 2001 From: uki00a Date: Tue, 13 Dec 2022 06:49:50 +0900 Subject: [PATCH 11/20] fix: improve retry logic --- connection.ts | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/connection.ts b/connection.ts index 5e425c67..e8d548ba 100644 --- a/connection.ts +++ b/connection.ts @@ -46,7 +46,6 @@ export class RedisConnection implements Connection { private readonly hostname: string; private readonly port: number | string; - private retryCount = 0; private _isClosed = false; private _isConnected = false; private backoff: Backoff; @@ -128,16 +127,21 @@ export class RedisConnection implements Connection { for (let i = 0; i < this.maxRetryCount; i++) { // Try to reconnect to the server and retry the command this.close(); - await this.connect(); - - const reply = await sendCommand( - this.writer, - this.reader, - command, - args, - ); - - return reply; + try { + await this.connect(); + + const reply = await sendCommand( + this.writer, + this.reader, + command, + args, + ); + + return reply; + } catch { // TODO: use `AggregateError`? + const backoff = this.backoff(i); + await delay(backoff); + } } throw error; @@ -148,6 +152,10 @@ export class RedisConnection implements Connection { * Connect to Redis server */ async connect(): Promise { + await this.#connect(0); + } + + async #connect(retryCount: number) { try { const dialOpts: Deno.ConnectOptions = { hostname: this.hostname, @@ -174,21 +182,18 @@ export class RedisConnection implements Connection { this.close(); throw error; } - this.retryCount = 0; } catch (error) { if (error instanceof AuthenticationError) { - this.retryCount = 0; throw (error.cause ?? error); } - if (this.retryCount++ >= this.maxRetryCount) { - this.retryCount = 0; + const backoff = this.backoff(retryCount); + retryCount++; + if (retryCount >= this.maxRetryCount) { throw error; } - - const backoff = this.backoff(this.retryCount); await delay(backoff); - await this.connect(); + await this.#connect(retryCount); } } From d6752ae2ad1eaa12c71a66f59b29963430948892 Mon Sep 17 00:00:00 2001 From: uki00a Date: Wed, 14 Dec 2022 06:08:15 +0900 Subject: [PATCH 12/20] chore: debug --- connection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/connection.ts b/connection.ts index e8d548ba..e34792c2 100644 --- a/connection.ts +++ b/connection.ts @@ -125,6 +125,7 @@ export class RedisConnection implements Connection { } for (let i = 0; i < this.maxRetryCount; i++) { + console.info(`retries ${i}`); // Try to reconnect to the server and retry the command this.close(); try { From 382b294dd1a7e3fc63cb23df94ca6fc566146d20 Mon Sep 17 00:00:00 2001 From: uki00a Date: Wed, 14 Dec 2022 06:14:35 +0900 Subject: [PATCH 13/20] fix: do not handle reconnection in Executor --- connection.ts | 5 ++--- errors.ts | 9 +++++++++ executor.ts | 17 +---------------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/connection.ts b/connection.ts index e34792c2..753a7aab 100644 --- a/connection.ts +++ b/connection.ts @@ -2,7 +2,7 @@ import { sendCommand } from "./protocol/mod.ts"; import type { RedisReply, RedisValue } from "./protocol/mod.ts"; import type { Backoff } from "./backoff.ts"; import { exponentialBackoff } from "./backoff.ts"; -import { ErrorReplyError } from "./errors.ts"; +import { ErrorReplyError, isRetriableError } from "./errors.ts"; import { BufReader, BufWriter, @@ -118,14 +118,13 @@ export class RedisConnection implements Connection { return reply; } catch (error) { if ( - !(error instanceof Deno.errors.BadResource) || + !isRetriableError(error) || this.isManuallyClosedByUser() ) { throw error; } for (let i = 0; i < this.maxRetryCount; i++) { - console.info(`retries ${i}`); // Try to reconnect to the server and retry the command this.close(); try { diff --git a/errors.ts b/errors.ts index f14bda62..1b4b4281 100644 --- a/errors.ts +++ b/errors.ts @@ -12,3 +12,12 @@ export class InvalidStateError extends Error { super(message ? `${base}: ${message}` : base); } } + +export function isRetriableError(error: Error): boolean { + return (error instanceof Deno.errors.BadResource || + error instanceof Deno.errors.BrokenPipe || + error instanceof Deno.errors.ConnectionAborted || + error instanceof Deno.errors.ConnectionRefused || + error instanceof Deno.errors.ConnectionReset || + error instanceof EOFError); +} diff --git a/executor.ts b/executor.ts index d917706e..dba8f45e 100644 --- a/executor.ts +++ b/executor.ts @@ -49,22 +49,7 @@ export class MuxExecutor implements CommandExecutor { if (!e) return; this.connection.sendCommand(e.command, ...e.args) .then(e.d.resolve) - .catch(async (error) => { - if ( - this.connection.maxRetryCount > 0 && - // Error `BadResource` is thrown when an attempt is made to write to a closed connection, - // Make sure that the connection wasn't explicitly closed by the user before trying to reconnect. - ((error instanceof Deno.errors.BadResource && - !this.connection.isClosed) || - error instanceof Deno.errors.BrokenPipe || - error instanceof Deno.errors.ConnectionAborted || - error instanceof Deno.errors.ConnectionRefused || - error instanceof Deno.errors.ConnectionReset || - error instanceof EOFError) - ) { - await this.connection.reconnect(); - } else e.d.reject(error); - }) + .catch(e.d.reject) .finally(() => { this.queue.shift(); this.dequeue(); From b401f583218feb145b23660570850323499aeed6 Mon Sep 17 00:00:00 2001 From: uki00a Date: Wed, 14 Dec 2022 06:15:36 +0900 Subject: [PATCH 14/20] chore: lint --- executor.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/executor.ts b/executor.ts index dba8f45e..23f269a5 100644 --- a/executor.ts +++ b/executor.ts @@ -1,5 +1,4 @@ import type { Connection } from "./connection.ts"; -import { EOFError } from "./errors.ts"; import { Deferred, deferred, From 2d9a414c7f3c88e969d65c3b33579c8ce7718e36 Mon Sep 17 00:00:00 2001 From: uki00a Date: Wed, 14 Dec 2022 06:18:16 +0900 Subject: [PATCH 15/20] fix: broken test --- tests/commands/general.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/commands/general.ts b/tests/commands/general.ts index 97501b62..6b433aa3 100644 --- a/tests/commands/general.ts +++ b/tests/commands/general.ts @@ -190,7 +190,7 @@ export function generalTests( const id = await tempClient.clientID(); await client.clientKill({ id }); const reply = await tempClient.ping(); - assertEquals(reply, "OK"); + assertEquals(reply, "PONG"); } finally { tempClient.close(); } From a2135509ec65833ef08c4c019c92ed6fffd7008b Mon Sep 17 00:00:00 2001 From: uki00a Date: Wed, 14 Dec 2022 06:28:20 +0900 Subject: [PATCH 16/20] chore: avoid using try-catch --- connection.ts | 66 +++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/connection.ts b/connection.ts index 753a7aab..8dd75849 100644 --- a/connection.ts +++ b/connection.ts @@ -104,48 +104,42 @@ export class RedisConnection implements Connection { await this.sendCommand("SELECT", db); } - async sendCommand( + sendCommand( command: string, ...args: Array ): Promise { - try { - const reply = await sendCommand( - this.writer, - this.reader, - command, - args, - ); - return reply; - } catch (error) { - if ( - !isRetriableError(error) || - this.isManuallyClosedByUser() - ) { - throw error; - } + return sendCommand(this.writer, this.reader, command, args).catch( + async (error) => { + if ( + !isRetriableError(error) || + this.isManuallyClosedByUser() + ) { + throw error; + } - for (let i = 0; i < this.maxRetryCount; i++) { - // Try to reconnect to the server and retry the command - this.close(); - try { - await this.connect(); - - const reply = await sendCommand( - this.writer, - this.reader, - command, - args, - ); - - return reply; - } catch { // TODO: use `AggregateError`? - const backoff = this.backoff(i); - await delay(backoff); + for (let i = 0; i < this.maxRetryCount; i++) { + // Try to reconnect to the server and retry the command + this.close(); + try { + await this.connect(); + + const reply = await sendCommand( + this.writer, + this.reader, + command, + args, + ); + + return reply; + } catch { // TODO: use `AggregateError`? + const backoff = this.backoff(i); + await delay(backoff); + } } - } - throw error; - } + throw error; + }, + ); } /** From 2ca99d7ec03fdb1fe090a88a4f080047fa2d8a04 Mon Sep 17 00:00:00 2001 From: uki00a Date: Sat, 17 Dec 2022 07:24:47 +0900 Subject: [PATCH 17/20] Revert "chore: avoid using try-catch" This reverts commit a2135509ec65833ef08c4c019c92ed6fffd7008b. --- connection.ts | 66 ++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/connection.ts b/connection.ts index 8dd75849..753a7aab 100644 --- a/connection.ts +++ b/connection.ts @@ -104,42 +104,48 @@ export class RedisConnection implements Connection { await this.sendCommand("SELECT", db); } - sendCommand( + async sendCommand( command: string, ...args: Array ): Promise { - return sendCommand(this.writer, this.reader, command, args).catch( - async (error) => { - if ( - !isRetriableError(error) || - this.isManuallyClosedByUser() - ) { - throw error; - } + try { + const reply = await sendCommand( + this.writer, + this.reader, + command, + args, + ); + return reply; + } catch (error) { + if ( + !isRetriableError(error) || + this.isManuallyClosedByUser() + ) { + throw error; + } - for (let i = 0; i < this.maxRetryCount; i++) { - // Try to reconnect to the server and retry the command - this.close(); - try { - await this.connect(); - - const reply = await sendCommand( - this.writer, - this.reader, - command, - args, - ); - - return reply; - } catch { // TODO: use `AggregateError`? - const backoff = this.backoff(i); - await delay(backoff); - } + for (let i = 0; i < this.maxRetryCount; i++) { + // Try to reconnect to the server and retry the command + this.close(); + try { + await this.connect(); + + const reply = await sendCommand( + this.writer, + this.reader, + command, + args, + ); + + return reply; + } catch { // TODO: use `AggregateError`? + const backoff = this.backoff(i); + await delay(backoff); } + } - throw error; - }, - ); + throw error; + } } /** From 84d134b5fdd9a377488622b7da711da1e3c4bb40 Mon Sep 17 00:00:00 2001 From: uki00a Date: Sun, 18 Dec 2022 23:13:58 +0900 Subject: [PATCH 18/20] fix: sendCommand signature --- connection.ts | 14 +++++++------- executor.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/connection.ts b/connection.ts index 753a7aab..2aed0231 100644 --- a/connection.ts +++ b/connection.ts @@ -21,7 +21,7 @@ export interface Connection { close(): void; connect(): Promise; reconnect(): Promise; - sendCommand(command: string, ...args: Array): Promise; + sendCommand(command: string, args?: Array): Promise; } export interface RedisConnectionOptions { @@ -84,8 +84,8 @@ export class RedisConnection implements Connection { ): Promise { try { password && username - ? await this.sendCommand("AUTH", username, password) - : await this.sendCommand("AUTH", password); + ? await this.sendCommand("AUTH", [username, password]) + : await this.sendCommand("AUTH", [password]); } catch (error) { if (error instanceof ErrorReplyError) { throw new AuthenticationError("Authentication failed", { @@ -101,19 +101,19 @@ export class RedisConnection implements Connection { db: number | undefined = this.options.db, ): Promise { if (!db) throw new Error("The database index is undefined."); - await this.sendCommand("SELECT", db); + await this.sendCommand("SELECT", [db]); } async sendCommand( command: string, - ...args: Array + args?: Array, ): Promise { try { const reply = await sendCommand( this.writer, this.reader, command, - args, + args ?? [], ); return reply; } catch (error) { @@ -134,7 +134,7 @@ export class RedisConnection implements Connection { this.writer, this.reader, command, - args, + args ?? [], ); return reply; diff --git a/executor.ts b/executor.ts index 23f269a5..e9548009 100644 --- a/executor.ts +++ b/executor.ts @@ -46,7 +46,7 @@ export class MuxExecutor implements CommandExecutor { private dequeue(): void { const [e] = this.queue; if (!e) return; - this.connection.sendCommand(e.command, ...e.args) + this.connection.sendCommand(e.command, e.args) .then(e.d.resolve) .catch(e.d.reject) .finally(() => { From 8746cc445e169e0b71f930c94bb0e6b5eb674357 Mon Sep 17 00:00:00 2001 From: uki00a Date: Sun, 18 Dec 2022 23:20:16 +0900 Subject: [PATCH 19/20] chore: use constant array --- connection.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/connection.ts b/connection.ts index 2aed0231..83533bde 100644 --- a/connection.ts +++ b/connection.ts @@ -37,6 +37,8 @@ export interface RedisConnectionOptions { backoff?: Backoff; } +const kEmptyRedisArgs: Array = []; + export class RedisConnection implements Connection { name: string | null = null; closer!: Closer; @@ -113,7 +115,7 @@ export class RedisConnection implements Connection { this.writer, this.reader, command, - args ?? [], + args ?? kEmptyRedisArgs, ); return reply; } catch (error) { @@ -134,7 +136,7 @@ export class RedisConnection implements Connection { this.writer, this.reader, command, - args ?? [], + args ?? kEmptyRedisArgs, ); return reply; From 81f6281011d3c5a42b30968e1edc707986791da4 Mon Sep 17 00:00:00 2001 From: uki00a Date: Sun, 18 Dec 2022 23:31:48 +0900 Subject: [PATCH 20/20] chore: add a test --- tests/commands/general.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/commands/general.ts b/tests/commands/general.ts index 6b433aa3..01e8f422 100644 --- a/tests/commands/general.ts +++ b/tests/commands/general.ts @@ -196,6 +196,20 @@ export function generalTests( } }); + it("fails when max retry count is exceeded", async () => { + const tempClient = await newClient({ + ...getOpts(), + maxRetryCount: 0, + }); + try { + const id = await tempClient.clientID(); + await client.clientKill({ id }); + await assertRejects(() => tempClient.ping()); + } finally { + tempClient.close(); + } + }); + it("does not reconnect when the connection is manually closed by the user", async () => { const tempClient = await newClient(getOpts()); tempClient.close();