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

start of work towards v3 release

This commit is contained in:
Salakar
2020-02-09 02:05:21 +00:00
parent 1d8fa45689
commit c0cc0bfab4
18 changed files with 234 additions and 400 deletions

143
index.js
View File

@@ -67,38 +67,16 @@ function RedisClient (options, stream) {
cnx_options.family = (!options.family && net.isIP(cnx_options.host)) || (options.family === 'IPv6' ? 6 : 4);
this.address = cnx_options.host + ':' + cnx_options.port;
}
// Warn on misusing deprecated functions
if (typeof options.retry_strategy === 'function') {
if ('max_attempts' in options) {
self.warn('WARNING: You activated the retry_strategy and max_attempts at the same time. This is not possible and max_attempts will be ignored.');
// Do not print deprecation warnings twice
delete options.max_attempts;
}
if ('retry_max_delay' in options) {
self.warn('WARNING: You activated the retry_strategy and retry_max_delay at the same time. This is not possible and retry_max_delay will be ignored.');
// Do not print deprecation warnings twice
delete options.retry_max_delay;
}
}
this.connection_options = cnx_options;
this.connection_id = RedisClient.connection_id++;
this.connected = false;
this.ready = false;
if (options.socket_nodelay === undefined) {
options.socket_nodelay = true;
} else if (!options.socket_nodelay) { // Only warn users with this set to false
self.warn(
'socket_nodelay is deprecated and will be removed in v.3.0.0.\n' +
'Setting socket_nodelay to false likely results in a reduced throughput. Please use .batch for pipelining instead.\n' +
'If you are sure you rely on the NAGLE-algorithm you can activate it by calling client.stream.setNoDelay(false) instead.'
);
}
if (options.socket_keepalive === undefined) {
options.socket_keepalive = true;
}
if (options.socket_initialdelay === undefined) {
options.socket_initialdelay = 0;
if (options.socket_initial_delay === undefined) {
options.socket_initial_delay = 0;
// set default to 0, which is aligned to https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay
}
for (var command in options.rename_commands) {
@@ -116,14 +94,6 @@ function RedisClient (options, stream) {
this.handle_reply = handle_detect_buffers_reply;
}
this.should_buffer = false;
this.max_attempts = options.max_attempts | 0;
if ('max_attempts' in options) {
self.warn(
'max_attempts is deprecated and will be removed in v.3.0.0.\n' +
'To reduce the number of options and to improve the reconnection handling please use the new `retry_strategy` option instead.\n' +
'This replaces the max_attempts and retry_max_delay option.'
);
}
this.command_queue = new Queue(); // Holds sent commands to de-pipeline them
this.offline_queue = new Queue(); // Holds commands issued but not able to be sent
this.pipeline_queue = new Queue(); // Holds all pipelined commands
@@ -131,14 +101,6 @@ function RedisClient (options, stream) {
// This should be done by the retry_strategy. Instead it should only be the timeout for connecting to redis
this.connect_timeout = +options.connect_timeout || 3600000; // 60 * 60 * 1000 ms
this.enable_offline_queue = options.enable_offline_queue === false ? false : true;
this.retry_max_delay = +options.retry_max_delay || null;
if ('retry_max_delay' in options) {
self.warn(
'retry_max_delay is deprecated and will be removed in v.3.0.0.\n' +
'To reduce the amount of options and the improve the reconnection handling please use the new `retry_strategy` option instead.\n' +
'This replaces the max_attempts and retry_max_delay option.'
);
}
this.initialize_retry_vars();
this.pub_sub_mode = 0;
this.subscription_set = {};
@@ -158,17 +120,7 @@ function RedisClient (options, stream) {
this.create_stream();
// The listeners will not be attached right away, so let's print the deprecation message while the listener is attached
this.on('newListener', function (event) {
if (event === 'idle') {
this.warn(
'The idle event listener is deprecated and will likely be removed in v.3.0.0.\n' +
'If you rely on this feature please open a new ticket in node_redis with your use case'
);
} else if (event === 'drain') {
this.warn(
'The drain event listener is deprecated and will be removed in v.3.0.0.\n' +
'If you want to keep on listening to this event please listen to the stream drain event directly.'
);
} else if ((event === 'message_buffer' || event === 'pmessage_buffer' || event === 'messageBuffer' || event === 'pmessageBuffer') && !this.buffers && !this.message_buffers) {
if ((event === 'message_buffer' || event === 'pmessage_buffer' || event === 'messageBuffer' || event === 'pmessageBuffer') && !this.buffers && !this.message_buffers) {
this.reply_parser.optionReturnBuffers = true;
this.message_buffers = true;
this.handle_reply = handle_detect_buffers_reply;
@@ -264,7 +216,6 @@ RedisClient.prototype.create_stream = function () {
// The buffer_from_socket.toString() has a significant impact on big chunks and therefore this should only be used if necessary
debug('Net read ' + self.address + ' id ' + self.connection_id); // + ': ' + buffer_from_socket.toString());
self.reply_parser.execute(buffer_from_socket);
self.emit_idle();
});
this.stream.on('error', function (err) {
@@ -283,9 +234,7 @@ RedisClient.prototype.create_stream = function () {
self.drain();
});
if (this.options.socket_nodelay) {
this.stream.setNoDelay();
}
this.stream.setNoDelay();
// Fire the command before redis is connected to be sure it's the first fired command
if (this.auth_pass !== undefined) {
@@ -387,7 +336,7 @@ RedisClient.prototype.on_error = function (err) {
this.connected = false;
this.ready = false;
// Only emit the error if the retry_stategy option is not set
// Only emit the error if the retry_strategy option is not set
if (!this.options.retry_strategy) {
this.emit('error', err);
}
@@ -402,7 +351,7 @@ RedisClient.prototype.on_connect = function () {
this.connected = true;
this.ready = false;
this.emitted_end = false;
this.stream.setKeepAlive(this.options.socket_keepalive, this.options.socket_initialdelay);
this.stream.setKeepAlive(this.options.socket_keepalive, this.options.socket_initial_delay);
this.stream.setTimeout(0);
this.emit('connect');
@@ -607,18 +556,31 @@ RedisClient.prototype.connection_gone = function (why, error) {
if (this.retry_delay instanceof Error) {
error = this.retry_delay;
}
var errorMessage = 'Redis connection in broken state: ';
if (this.retry_totaltime >= this.connect_timeout) {
errorMessage += 'connection timeout exceeded.';
} else {
errorMessage += 'maximum connection attempts exceeded.';
}
this.flush_and_error({
message: 'Stream connection ended and command aborted.',
code: 'NR_CLOSED'
message: errorMessage,
code: 'CONNECTION_BROKEN',
}, {
error: error
});
var retryError = new Error(errorMessage);
retryError.code = 'CONNECTION_BROKEN';
if (error) {
retryError.origin = error;
}
this.end(false);
this.emit('error', retryError);
return;
}
}
if (this.max_attempts !== 0 && this.attempts >= this.max_attempts || this.retry_totaltime >= this.connect_timeout) {
if (this.retry_totaltime >= this.connect_timeout) {
var message = 'Redis connection in broken state: ';
if (this.retry_totaltime >= this.connect_timeout) {
message += 'connection timeout exceeded.';
@@ -637,8 +599,8 @@ RedisClient.prototype.connection_gone = function (why, error) {
if (error) {
err.origin = error;
}
this.emit('error', err);
this.end(false);
this.emit('error', err);
return;
}
@@ -656,15 +618,12 @@ RedisClient.prototype.connection_gone = function (why, error) {
});
}
if (this.retry_max_delay !== null && this.retry_delay > this.retry_max_delay) {
this.retry_delay = this.retry_max_delay;
} else if (this.retry_totaltime + this.retry_delay > this.connect_timeout) {
if (this.retry_totaltime + this.retry_delay > this.connect_timeout) {
// Do not exceed the maximum
this.retry_delay = this.connect_timeout - this.retry_totaltime;
}
debug('Retry connection in ' + this.retry_delay + ' ms');
this.retry_timer = setTimeout(retry_connection, this.retry_delay, this, error);
};
@@ -693,16 +652,9 @@ RedisClient.prototype.return_error = function (err) {
};
RedisClient.prototype.drain = function () {
this.emit('drain');
this.should_buffer = false;
};
RedisClient.prototype.emit_idle = function () {
if (this.command_queue.length === 0 && this.pub_sub_mode === 0) {
this.emit('idle');
}
};
function normal_reply (self, reply) {
var command_obj = self.command_queue.shift();
if (typeof command_obj.callback === 'function') {
@@ -752,7 +704,7 @@ function subscribe_unsubscribe (self, reply, type) {
self.command_queue.shift();
if (typeof command_obj.callback === 'function') {
// TODO: The current return value is pretty useless.
// Evaluate to change this in v.3 to return all subscribed / unsubscribed channels in an array including the number of channels subscribed too
// Evaluate to change this in v.4 to return all subscribed / unsubscribed channels in an array including the number of channels subscribed too
command_obj.callback(null, channel);
}
self.sub_commands_left = 0;
@@ -768,7 +720,7 @@ function subscribe_unsubscribe (self, reply, type) {
function return_pub_sub (self, reply) {
var type = reply[0].toString();
if (type === 'message') { // channel, message
if (!self.options.return_buffers || self.message_buffers) { // backwards compatible. Refactor this in v.3 to always return a string on the normal emitter
if (!self.options.return_buffers || self.message_buffers) { // backwards compatible. Refactor this in v.4 to always return a string on the normal emitter
self.emit('message', reply[1].toString(), reply[2].toString());
self.emit('message_buffer', reply[1], reply[2]);
self.emit('messageBuffer', reply[1], reply[2]);
@@ -776,7 +728,7 @@ function return_pub_sub (self, reply) {
self.emit('message', reply[1], reply[2]);
}
} else if (type === 'pmessage') { // pattern, channel, message
if (!self.options.return_buffers || self.message_buffers) { // backwards compatible. Refactor this in v.3 to always return a string on the normal emitter
if (!self.options.return_buffers || self.message_buffers) { // backwards compatible. Refactor this in v.4 to always return a string on the normal emitter
self.emit('pmessage', reply[1].toString(), reply[2].toString(), reply[3].toString());
self.emit('pmessage_buffer', reply[1], reply[2], reply[3]);
self.emit('pmessageBuffer', reply[1], reply[2], reply[3]);
@@ -884,32 +836,39 @@ RedisClient.prototype.internal_send_command = function (command_obj) {
} else if (typeof args[i] === 'object') { // Checking for object instead of Buffer.isBuffer helps us finding data types that we can't handle properly
if (args[i] instanceof Date) { // Accept dates as valid input
args_copy[i] = args[i].toString();
} else if (args[i] === null) {
this.warn(
'Deprecated: The ' + command.toUpperCase() + ' command contains a "null" argument.\n' +
'This is converted to a "null" string now and will return an error from v.3.0 on.\n' +
'Please handle this in your code to make sure everything works as you intended it to.'
);
args_copy[i] = 'null'; // Backwards compatible :/
} else if (Buffer.isBuffer(args[i])) {
args_copy[i] = args[i];
command_obj.buffer_args = true;
big_data = true;
} else {
this.warn(
'Deprecated: The ' + command.toUpperCase() + ' command contains a argument of type ' + args[i].constructor.name + '.\n' +
'This is converted to "' + args[i].toString() + '" by using .toString() now and will return an error from v.3.0 on.\n' +
'Please handle this in your code to make sure everything works as you intended it to.'
var invalidArgError = new Error(
'node_redis: The ' + command.toUpperCase() + ' command contains a invalid argument type.\n' +
'Only strings, dates and buffers are accepted. Please update your code to use valid argument types.'
);
args_copy[i] = args[i].toString(); // Backwards compatible :/
invalidArgError.command = command_obj.command.toUpperCase();
if (command_obj.args && command_obj.args.length) {
invalidArgError.args = command_obj.args;
}
if (command_obj.callback) {
command_obj.callback(invalidArgError);
return false;
}
throw invalidArgError;
}
} else if (typeof args[i] === 'undefined') {
this.warn(
'Deprecated: The ' + command.toUpperCase() + ' command contains a "undefined" argument.\n' +
'This is converted to a "undefined" string now and will return an error from v.3.0 on.\n' +
'Please handle this in your code to make sure everything works as you intended it to.'
var undefinedArgError = new Error(
'node_redis: The ' + command.toUpperCase() + ' command contains a invalid argument type of "undefined".\n' +
'Only strings, dates and buffers are accepted. Please update your code to use valid argument types.'
);
args_copy[i] = 'undefined'; // Backwards compatible :/
undefinedArgError.command = command_obj.command.toUpperCase();
if (command_obj.args && command_obj.args.length) {
undefinedArgError.args = command_obj.args;
}
if (command_obj.callback) {
command_obj.callback(undefinedArgError);
return false;
}
throw undefinedArgError;
} else {
// Seems like numbers are converted fast using string concatenation
args_copy[i] = '' + args[i];