From b76035bf6e6faa4e09b851caad379b24d35388f0 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Tue, 1 Nov 2022 20:06:48 -0400 Subject: [PATCH 1/4] fix #1598 fix #2276 - add `pingInterval` to client config --- docs/client-configuration.md | 1 + packages/client/lib/client/index.spec.ts | 14 ++++++++++++++ packages/client/lib/client/index.ts | 22 +++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/client-configuration.md b/docs/client-configuration.md index 6b7e7da7532..719f457ef36 100644 --- a/docs/client-configuration.md +++ b/docs/client-configuration.md @@ -25,6 +25,7 @@ | readonly | `false` | Connect in [`READONLY`](https://redis.io/commands/readonly) mode | | legacyMode | `false` | Maintain some backwards compatibility (see the [Migration Guide](./v3-to-v4.md)) | | isolationPoolOptions | | See the [Isolated Execution Guide](./isolated-execution.md) | +| pingInterval | | Send `PING` command on interval (in ms). Useful with "[Azure Cache for Redis](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection#idle-timeout)" | ## Reconnect Strategy diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index 27cb86d657e..b9f7851a470 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -862,4 +862,18 @@ describe('Client', () => { client.unref(); client.ref(); }, GLOBAL.SERVERS.OPEN); + + describe.only('', () => { + testUtils.testWithClient('pingInterval', async client => { + assert.deepEqual( + await once(client, 'ping-interval'), + ['PONG'] + ); + }, { + ...GLOBAL.SERVERS.OPEN, + clientOptions: { + pingInterval: 1 + } + }); + }); }); diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts index 52895c73c3e..770b90b2062 100644 --- a/packages/client/lib/client/index.ts +++ b/packages/client/lib/client/index.ts @@ -31,6 +31,7 @@ export interface RedisClientOptions< readonly?: boolean; legacyMode?: boolean; isolationPoolOptions?: PoolOptions; + pingInterval?: number; } type WithCommands = { @@ -281,7 +282,10 @@ export default class RedisClient< this.#queue.flushAll(err); } }) - .on('connect', () => this.emit('connect')) + .on('connect', () => { + this.emit('connect'); + this.#setPingTimer(); + }) .on('ready', () => { this.emit('ready'); this.#tick(); @@ -348,6 +352,22 @@ export default class RedisClient< (...args: Array): void => (this as any).sendCommand(name, ...args); } + #pingTimer?: NodeJS.Timer; + + #setPingTimer(): void { + if (!this.#options?.pingInterval || !this.#socket.isOpen) return; + clearTimeout(this.#pingTimer); + + this.#pingTimer = setTimeout(() => { + if (!this.#socket.isOpen) return; + + (this as unknown as RedisClientType).ping() + .then(reply => this.emit('ping-interval', reply)) + .catch(err => this.emit('error', err)) + .finally(() => this.#setPingTimer()); + }, this.#options.pingInterval); + } + duplicate(overrides?: Partial>): RedisClientType { return new (Object.getPrototypeOf(this).constructor)({ ...this.#options, From e225d5b469c953d539dc91aaff75a6d745057943 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Mon, 7 Nov 2022 04:37:38 -0500 Subject: [PATCH 2/4] setPingTimer on ready (instead of on connect) --- packages/client/lib/client/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts index 770b90b2062..a50a18adea2 100644 --- a/packages/client/lib/client/index.ts +++ b/packages/client/lib/client/index.ts @@ -284,10 +284,10 @@ export default class RedisClient< }) .on('connect', () => { this.emit('connect'); - this.#setPingTimer(); }) .on('ready', () => { this.emit('ready'); + this.#setPingTimer(); this.#tick(); }) .on('reconnecting', () => this.emit('reconnecting')) From 06178235e94f35bdfb68c9d1790a19f2874cab6b Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Mon, 7 Nov 2022 04:50:28 -0500 Subject: [PATCH 3/4] use isReady (instead of isOpen) and fix test --- packages/client/lib/client/index.spec.ts | 22 ++++++++++------------ packages/client/lib/client/index.ts | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index b9f7851a470..6294e155a44 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -863,17 +863,15 @@ describe('Client', () => { client.ref(); }, GLOBAL.SERVERS.OPEN); - describe.only('', () => { - testUtils.testWithClient('pingInterval', async client => { - assert.deepEqual( - await once(client, 'ping-interval'), - ['PONG'] - ); - }, { - ...GLOBAL.SERVERS.OPEN, - clientOptions: { - pingInterval: 1 - } - }); + testUtils.testWithClient('pingInterval', async client => { + assert.deepEqual( + await once(client, 'ping-interval'), + ['PONG'] + ); + }, { + ...GLOBAL.SERVERS.OPEN, + clientOptions: { + pingInterval: 1 + } }); }); diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts index a50a18adea2..e6f1fef10e5 100644 --- a/packages/client/lib/client/index.ts +++ b/packages/client/lib/client/index.ts @@ -355,11 +355,11 @@ export default class RedisClient< #pingTimer?: NodeJS.Timer; #setPingTimer(): void { - if (!this.#options?.pingInterval || !this.#socket.isOpen) return; + if (!this.#options?.pingInterval || !this.#socket.isReady) return; clearTimeout(this.#pingTimer); this.#pingTimer = setTimeout(() => { - if (!this.#socket.isOpen) return; + if (!this.#socket.isReady) return; (this as unknown as RedisClientType).ping() .then(reply => this.emit('ping-interval', reply)) From 6e0a302cda0167332a582f87d2abd8130d2f3df2 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Thu, 10 Nov 2022 03:48:48 -0500 Subject: [PATCH 4/4] Update client-configuration.md --- docs/client-configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/client-configuration.md b/docs/client-configuration.md index 719f457ef36..a67cef462ac 100644 --- a/docs/client-configuration.md +++ b/docs/client-configuration.md @@ -25,7 +25,7 @@ | readonly | `false` | Connect in [`READONLY`](https://redis.io/commands/readonly) mode | | legacyMode | `false` | Maintain some backwards compatibility (see the [Migration Guide](./v3-to-v4.md)) | | isolationPoolOptions | | See the [Isolated Execution Guide](./isolated-execution.md) | -| pingInterval | | Send `PING` command on interval (in ms). Useful with "[Azure Cache for Redis](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection#idle-timeout)" | +| pingInterval | | Send `PING` command at interval (in ms). Useful with "[Azure Cache for Redis](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection#idle-timeout)" | ## Reconnect Strategy