Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions lib/Redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class Redis extends Commander implements DataHandledable {
private connectionEpoch = 0;
private retryAttempts = 0;
private manuallyClosing = false;
private socketTimeoutTimer: NodeJS.Timeout | undefined;

// Prepare autopipelines structures
private _autoPipelines = new Map();
Expand Down Expand Up @@ -523,6 +524,10 @@ class Redis extends Commander implements DataHandledable {
if (Command.checkFlag("WILL_DISCONNECT", command.name)) {
this.manuallyClosing = true;
}

if (this.options.socketTimeout !== undefined && this.socketTimeoutTimer === undefined) {
this.setSocketTimeout();
}
}

if (command.name === "select" && isInt(command.args[0])) {
Expand All @@ -537,6 +542,23 @@ class Redis extends Commander implements DataHandledable {
return command.promise;
}

private setSocketTimeout() {
this.socketTimeoutTimer = setTimeout(() => {
this.stream.destroy(new Error(`Socket timeout. Expecting data, but didn't receive any in ${this.options.socketTimeout}ms.`));
this.socketTimeoutTimer = undefined;
}, this.options.socketTimeout);

// this handler must run after the "data" handler in "DataHandler"
// so that `this.commandQueue.length` will be updated
this.stream.once("data", () => {
console.log('GOT DATA, CLEARING TIMER');
clearTimeout(this.socketTimeoutTimer);
this.socketTimeoutTimer = undefined;
if (this.commandQueue.length === 0) return;
this.setSocketTimeout();
});
}

scanStream(options?: ScanStreamOptions) {
return this.createScanStream("scan", { options });
}
Expand Down
9 changes: 9 additions & 0 deletions lib/redis/RedisOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ export interface CommonRedisOptions extends CommanderOptions {
* a "Command timed out" error will be thrown.
*/
commandTimeout?: number;

/**
* If the socket does not receive data within a set number of milliseconds:
* 1. the socket is considered "dead" and will be destroyed
* 2. the client will reject any running commands (altought they might have been processed by the server)
* 3. the reconnect strategy will kick in (depending on the configuration)
*/
socketTimeout?: number;

/**
* Enable/disable keep-alive functionality.
* @link https://nodejs.org/api/net.html#socketsetkeepaliveenable-initialdelay
Expand Down