1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-09 00:22:08 +03:00

fix(client): Avoids infinite promise-chaining when socket's creation fails (#2295)

* fix(client): timeout issues during tests

* fix(client): avoiding infinite Promise chaining while socket creation fails

* fix(client): Added missing semicolons

* clean test

Co-authored-by: leibale <leibale1998@gmail.com>
This commit is contained in:
Jonas Faure
2022-10-26 22:42:52 +02:00
committed by GitHub
parent c413657357
commit 252c2192ea
2 changed files with 43 additions and 43 deletions

View File

@@ -1,5 +1,5 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import { SinonFakeTimers, useFakeTimers, spy } from 'sinon'; import { spy } from 'sinon';
import RedisSocket, { RedisSocketOptions } from './socket'; import RedisSocket, { RedisSocketOptions } from './socket';
describe('Socket', () => { describe('Socket', () => {
@@ -9,37 +9,34 @@ describe('Socket', () => {
options options
); );
socket.on('error', (err) => { socket.on('error', () => {
// ignore errors // ignore errors
console.log(err);
}); });
return socket; return socket;
} }
describe('reconnectStrategy', () => { describe('reconnectStrategy', () => {
let clock: SinonFakeTimers;
beforeEach(() => clock = useFakeTimers());
afterEach(() => clock.restore());
it('custom strategy', async () => { it('custom strategy', async () => {
const numberOfRetries = 10;
const reconnectStrategy = spy((retries: number) => { const reconnectStrategy = spy((retries: number) => {
assert.equal(retries + 1, reconnectStrategy.callCount); assert.equal(retries + 1, reconnectStrategy.callCount);
if (retries === 50) return new Error('50'); if (retries === numberOfRetries) return new Error(`${numberOfRetries}`);
const time = retries * 2; const time = retries * 2;
queueMicrotask(() => clock.tick(time));
return time; return time;
}); });
const socket = createSocket({ const socket = createSocket({
host: 'error', host: 'error',
connectTimeout: 1,
reconnectStrategy reconnectStrategy
}); });
await assert.rejects(socket.connect(), { await assert.rejects(socket.connect(), {
message: '50' message: `${numberOfRetries}`
}); });
assert.equal(socket.isOpen, false); assert.equal(socket.isOpen, false);
@@ -48,9 +45,9 @@ describe('Socket', () => {
it('should handle errors', async () => { it('should handle errors', async () => {
const socket = createSocket({ const socket = createSocket({
host: 'error', host: 'error',
connectTimeout: 1,
reconnectStrategy(retries: number) { reconnectStrategy(retries: number) {
if (retries === 1) return new Error('done'); if (retries === 1) return new Error('done');
queueMicrotask(() => clock.tick(500));
throw new Error(); throw new Error();
} }
}); });

View File

@@ -105,10 +105,12 @@ export default class RedisSocket extends EventEmitter {
throw new Error('Socket already opened'); throw new Error('Socket already opened');
} }
return this.#connect(0); return this.#connect();
} }
async #connect(retries: number, hadError?: boolean): Promise<void> { async #connect(hadError?: boolean): Promise<void> {
let retries = 0;
do {
if (retries > 0 || hadError) { if (retries > 0 || hadError) {
this.emit('reconnecting'); this.emit('reconnecting');
} }
@@ -138,13 +140,14 @@ export default class RedisSocket extends EventEmitter {
this.emit('error', err); this.emit('error', err);
await promiseTimeout(retryIn); await promiseTimeout(retryIn);
return this.#connect(retries + 1);
} }
retries++;
} while (!this.#isReady);
} }
#createSocket(): Promise<net.Socket | tls.TLSSocket> { #createSocket(): Promise<net.Socket | tls.TLSSocket> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const {connectEvent, socket} = RedisSocket.#isTlsSocket(this.#options) ? const { connectEvent, socket } = RedisSocket.#isTlsSocket(this.#options) ?
this.#createTlsSocket() : this.#createTlsSocket() :
this.#createNetSocket(); this.#createNetSocket();
@@ -200,7 +203,7 @@ export default class RedisSocket extends EventEmitter {
this.#isReady = false; this.#isReady = false;
this.emit('error', err); this.emit('error', err);
this.#connect(0, true).catch(() => { this.#connect(true).catch(() => {
// the error was already emitted, silently ignore it // the error was already emitted, silently ignore it
}); });
} }