From 3c2f7ab92a3665d144d0617121ac4ebcccf78aed Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Thu, 10 Nov 2022 03:49:56 -0500 Subject: [PATCH] Ping interval (#2321) * fix #1598 fix #2276 - add `pingInterval` to client config * setPingTimer on ready (instead of on connect) * use isReady (instead of isOpen) and fix test * Update client-configuration.md --- docs/client-configuration.md | 1 + packages/client/lib/client/index.spec.ts | 12 ++++++++++++ packages/client/lib/client/index.ts | 22 +++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/client-configuration.md b/docs/client-configuration.md index 6b7e7da753..a67cef462a 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 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 diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index 27cb86d657..6294e155a4 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -862,4 +862,16 @@ describe('Client', () => { client.unref(); client.ref(); }, GLOBAL.SERVERS.OPEN); + + 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 52895c73c3..e6f1fef10e 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,9 +282,12 @@ export default class RedisClient< this.#queue.flushAll(err); } }) - .on('connect', () => this.emit('connect')) + .on('connect', () => { + this.emit('connect'); + }) .on('ready', () => { this.emit('ready'); + this.#setPingTimer(); this.#tick(); }) .on('reconnecting', () => this.emit('reconnecting')) @@ -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.isReady) return; + clearTimeout(this.#pingTimer); + + this.#pingTimer = setTimeout(() => { + if (!this.#socket.isReady) 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,