Skip to content

Commit 3c2f7ab

Browse files
authored
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
1 parent e0e96ae commit 3c2f7ab

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

docs/client-configuration.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
| readonly | `false` | Connect in [`READONLY`](https://redis.io/commands/readonly) mode |
2626
| legacyMode | `false` | Maintain some backwards compatibility (see the [Migration Guide](./v3-to-v4.md)) |
2727
| isolationPoolOptions | | See the [Isolated Execution Guide](./isolated-execution.md) |
28+
| 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)" |
2829

2930
## Reconnect Strategy
3031

packages/client/lib/client/index.spec.ts

+12
Original file line numberDiff line numberDiff line change
@@ -862,4 +862,16 @@ describe('Client', () => {
862862
client.unref();
863863
client.ref();
864864
}, GLOBAL.SERVERS.OPEN);
865+
866+
testUtils.testWithClient('pingInterval', async client => {
867+
assert.deepEqual(
868+
await once(client, 'ping-interval'),
869+
['PONG']
870+
);
871+
}, {
872+
...GLOBAL.SERVERS.OPEN,
873+
clientOptions: {
874+
pingInterval: 1
875+
}
876+
});
865877
});

packages/client/lib/client/index.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface RedisClientOptions<
3131
readonly?: boolean;
3232
legacyMode?: boolean;
3333
isolationPoolOptions?: PoolOptions;
34+
pingInterval?: number;
3435
}
3536

3637
type WithCommands = {
@@ -281,9 +282,12 @@ export default class RedisClient<
281282
this.#queue.flushAll(err);
282283
}
283284
})
284-
.on('connect', () => this.emit('connect'))
285+
.on('connect', () => {
286+
this.emit('connect');
287+
})
285288
.on('ready', () => {
286289
this.emit('ready');
290+
this.#setPingTimer();
287291
this.#tick();
288292
})
289293
.on('reconnecting', () => this.emit('reconnecting'))
@@ -348,6 +352,22 @@ export default class RedisClient<
348352
(...args: Array<unknown>): void => (this as any).sendCommand(name, ...args);
349353
}
350354

355+
#pingTimer?: NodeJS.Timer;
356+
357+
#setPingTimer(): void {
358+
if (!this.#options?.pingInterval || !this.#socket.isReady) return;
359+
clearTimeout(this.#pingTimer);
360+
361+
this.#pingTimer = setTimeout(() => {
362+
if (!this.#socket.isReady) return;
363+
364+
(this as unknown as RedisClientType<M, F, S>).ping()
365+
.then(reply => this.emit('ping-interval', reply))
366+
.catch(err => this.emit('error', err))
367+
.finally(() => this.#setPingTimer());
368+
}, this.#options.pingInterval);
369+
}
370+
351371
duplicate(overrides?: Partial<RedisClientOptions<M, F, S>>): RedisClientType<M, F, S> {
352372
return new (Object.getPrototypeOf(this).constructor)({
353373
...this.#options,

0 commit comments

Comments
 (0)