From 48dced2b855bd934897ff85ad3384385830a670a Mon Sep 17 00:00:00 2001 From: yahiro <321700+yahiro07@users.noreply.github.com> Date: Fri, 29 Mar 2024 09:01:09 +0900 Subject: [PATCH] fix: auto reconnection hangs (#431) Closes #431 --------- Co-authored-by: yahiro --- connection.ts | 18 ++++++++++++++---- tests/reconnect_test.ts | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/reconnect_test.ts diff --git a/connection.ts b/connection.ts index 615a91a3..eaf44623 100644 --- a/connection.ts +++ b/connection.ts @@ -19,6 +19,13 @@ export interface SendCommandOptions { * @default false */ returnUint8Arrays?: boolean; + + /** + * When this option is set, the command is executed directly without queueing. + * + * @default false + */ + inline?: boolean; } export interface Connection { @@ -126,8 +133,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], { inline: true }) + : await this.sendCommand("AUTH", [password], { inline: true }); } catch (error) { if (error instanceof ErrorReplyError) { throw new AuthenticationError("Authentication failed", { @@ -143,7 +150,7 @@ 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], { inline: true }); } private enqueueCommand( @@ -160,13 +167,16 @@ export class RedisConnection implements Connection { args?: Array, options?: SendCommandOptions, ): Promise { - const { promise, resolve, reject } = Promise.withResolvers(); const execute = () => this.#protocol.sendCommand( command, args ?? kEmptyRedisArgs, options?.returnUint8Arrays, ); + if (options?.inline) { + return execute(); + } + const { promise, resolve, reject } = Promise.withResolvers(); this.enqueueCommand({ execute, resolve, reject }); return promise; diff --git a/tests/reconnect_test.ts b/tests/reconnect_test.ts new file mode 100644 index 00000000..83518eff --- /dev/null +++ b/tests/reconnect_test.ts @@ -0,0 +1,36 @@ +import { assertEquals } from "../vendor/https/deno.land/std/assert/mod.ts"; +import { + beforeAll, + describe, + it, +} from "../vendor/https/deno.land/std/testing/bdd.ts"; +import { newClient, nextPort, startRedis, stopRedis } from "./test_util.ts"; + +describe("reconnect", () => { + let port!: number; + beforeAll(() => { + port = nextPort(); + }); + + it("auto reconnect", async () => { + let server = await startRedis({ port }); + const client = await newClient({ hostname: "127.0.0.1", port }); + assertEquals(await client.ping(), "PONG"); + await stopRedis(server); + server = await startRedis({ port }); + assertEquals(await client.ping(), "PONG"); + client.close(); + await stopRedis(server); + }); + + it("auto reconnect, with db spec", async () => { + let server = await startRedis({ port }); + const client = await newClient({ hostname: "127.0.0.1", port, db: 1 }); + assertEquals(await client.ping(), "PONG"); + await stopRedis(server); + server = await startRedis({ port }); + assertEquals(await client.ping(), "PONG"); + client.close(); + await stopRedis(server); + }); +});