Skip to content

Commit 575ad73

Browse files
author
Ruben Bridgewater
committed
Insert deprecation warnings and some minor refactoring
1 parent 19ea518 commit 575ad73

File tree

9 files changed

+140
-46
lines changed

9 files changed

+140
-46
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ So please attach the error listener to node_redis.
147147

148148
`client` will emit `end` when an established Redis server connection has closed.
149149

150-
### "drain"
150+
### "drain" (deprecated)
151151

152152
`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now
153153
writable. This event can be used to stream commands in to Redis and adapt to backpressure.
@@ -162,20 +162,21 @@ If false is returned the stream had to buffer.
162162

163163
`client` will emit `warning` when password was set but none is needed and if a deprecated option / function / similar is used.
164164

165-
### "idle"
165+
### "idle" (deprecated)
166166

167167
`client` will emit `idle` when there are no outstanding commands that are awaiting a response.
168168

169169
## redis.createClient()
170170
If you have `redis-server` running on the same computer as node, then the defaults for
171171
port and host are probably fine and you don't need to supply any arguments. `createClient()` returns a `RedisClient` object.
172172

173+
If the redis server runs on the same machine as the client consider using unix sockets if possible to increase throughput.
174+
173175
### overloading
174-
* `redis.createClient()`
175-
* `redis.createClient(options)`
176-
* `redis.createClient(unix_socket, options)`
177-
* `redis.createClient(redis_url, options)`
178-
* `redis.createClient(port, host, options)`
176+
* `redis.createClient([options])`
177+
* `redis.createClient(unix_socket[, options])`
178+
* `redis.createClient(redis_url[, options])`
179+
* `redis.createClient(port[, host][, options])`
179180

180181
#### `options` is an object with the following possible properties:
181182
* `host`: *127.0.0.1*; The host to connect to
@@ -204,10 +205,10 @@ This delay normally grows infinitely, but setting `retry_max_delay` limits it to
204205
* `connect_timeout`: *3600000*; Setting `connect_timeout` limits total time for client to connect and reconnect.
205206
The value is provided in milliseconds and is counted from the moment on a new client is created / a connection is lost. The last retry is going to happen exactly at the timeout time.
206207
Default is to try connecting until the default system socket timeout has been exceeded and to try reconnecting until 1h passed.
207-
* `max_attempts`: *0*; By default client will try reconnecting until connected. Setting `max_attempts`
208+
* `max_attempts`: *0*; (Deprecated, please use `retry_strategy` instead) By default client will try reconnecting until connected. Setting `max_attempts`
208209
limits total amount of connection tries. Setting this to 1 will prevent any reconnect tries.
209210
* `retry_unfulfilled_commands`: *false*; If set to true, all commands that were unfulfulled while the connection is lost will be retried after the connection has reestablished again. Use this with caution, if you use state altering commands (e.g. *incr*). This is especially useful if you use blocking commands.
210-
* `password`: *null*; If set, client will run redis auth command on connect. Alias `auth_pass`
211+
* `password`: *null*; If set, client will run redis auth command on connect. Alias `auth_pass` (node_redis < 2.5 have to use auth_pass)
211212
* `db`: *null*; If set, client will run redis select command on connect. This is [not recommended](https://groups.google.com/forum/#!topic/redis-db/vS5wX8X4Cjg).
212213
* `family`: *IPv4*; You can force using IPv6 if you set the family to 'IPv6'. See Node.js [net](https://nodejs.org/api/net.html) or [dns](https://nodejs.org/api/dns.html) modules how to use the family type.
213214
* `disable_resubscribing`: *false*; If set to `true`, a client won't resubscribe after disconnecting

index.js

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,32 @@ function RedisClient (options) {
5151
for (var tls_option in options.tls) { // jshint ignore: line
5252
cnx_options[tls_option] = options.tls[tls_option];
5353
}
54+
// Warn on misusing deprecated functions
55+
if (typeof options.retry_strategy === 'function') {
56+
if ('max_attempts' in options) {
57+
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.');
58+
// Do not print deprecation warnings twice
59+
delete options.max_attempts;
60+
}
61+
if ('retry_max_delay' in options) {
62+
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.');
63+
// Do not print deprecation warnings twice
64+
delete options.retry_max_delay;
65+
}
66+
}
67+
5468
this.connection_options = cnx_options;
55-
this.connection_id = ++connection_id;
69+
this.connection_id = RedisClient.connection_id++;
5670
this.connected = false;
5771
this.ready = false;
5872
if (options.socket_nodelay === undefined) {
5973
options.socket_nodelay = true;
6074
} else if (!options.socket_nodelay) { // Only warn users with this set to false
61-
process.nextTick(function () {
62-
self.warn(
63-
'socket_nodelay is deprecated and will be removed in v.3.0.0.\n' +
64-
'Setting socket_nodelay to false likely results in a reduced throughput. Please use .batch to buffer commands and use pipelining.\n' +
65-
'If you are sure you rely on the NAGLE-algorithm you can activate it by calling client.stream.setNoDelay(false) instead.'
66-
);
67-
});
75+
self.warn(
76+
'socket_nodelay is deprecated and will be removed in v.3.0.0.\n' +
77+
'Setting socket_nodelay to false likely results in a reduced throughput. Please use .batch for pipelining instead.\n' +
78+
'If you are sure you rely on the NAGLE-algorithm you can activate it by calling client.stream.setNoDelay(false) instead.'
79+
);
6880
}
6981
if (options.socket_keepalive === undefined) {
7082
options.socket_keepalive = true;
@@ -76,9 +88,7 @@ function RedisClient (options) {
7688
options.detect_buffers = !!options.detect_buffers;
7789
// Override the detect_buffers setting if return_buffers is active and print a warning
7890
if (options.return_buffers && options.detect_buffers) {
79-
process.nextTick(function () {
80-
self.warn('WARNING: You activated return_buffers and detect_buffers at the same time. The return value is always going to be a buffer.');
81-
});
91+
self.warn('WARNING: You activated return_buffers and detect_buffers at the same time. The return value is always going to be a buffer.');
8292
options.detect_buffers = false;
8393
}
8494
if (options.detect_buffers) {
@@ -87,11 +97,27 @@ function RedisClient (options) {
8797
}
8898
this.should_buffer = false;
8999
this.max_attempts = options.max_attempts | 0;
100+
if ('max_attempts' in options) {
101+
self.warn(
102+
'max_attempts is deprecated and will be removed in v.3.0.0.\n' +
103+
'To reduce the amount of options and the improve the reconnection handling please use the new `retry_strategy` option instead.\n' +
104+
'This replaces the max_attempts and retry_max_delay option.'
105+
);
106+
}
90107
this.command_queue = new Queue(); // Holds sent commands to de-pipeline them
91108
this.offline_queue = new Queue(); // Holds commands issued but not able to be sent
109+
// ATTENTION: connect_timeout should change in v.3.0 so it does not count towards ending reconnection attempts after x seconds
110+
// This should be done by the retry_strategy. Instead it should only be the timeout for connecting to redis
92111
this.connect_timeout = +options.connect_timeout || 3600000; // 60 * 60 * 1000 ms
93112
this.enable_offline_queue = options.enable_offline_queue === false ? false : true;
94113
this.retry_max_delay = +options.retry_max_delay || null;
114+
if ('retry_max_delay' in options) {
115+
self.warn(
116+
'retry_max_delay is deprecated and will be removed in v.3.0.0.\n' +
117+
'To reduce the amount of options and the improve the reconnection handling please use the new `retry_strategy` option instead.\n' +
118+
'This replaces the max_attempts and retry_max_delay option.'
119+
);
120+
}
95121
this.initialize_retry_vars();
96122
this.pub_sub_mode = false;
97123
this.subscription_set = {};
@@ -123,8 +149,24 @@ function RedisClient (options) {
123149
name: options.parser
124150
});
125151
this.create_stream();
152+
// The listeners will not be attached right away, so let's print the deprecation message while the listener is attached
153+
this.on('newListener', function (event) {
154+
if (event === 'idle') {
155+
this.warn(
156+
'The idle event listener is deprecated and will likely be removed in v.3.0.0.\n' +
157+
'If you rely on this feature please open a new ticket in node_redis with your use case'
158+
);
159+
} else if (event === 'drain') {
160+
this.warn(
161+
'The drain event listener is deprecated and will be removed in v.3.0.0.\n' +
162+
'If you want to keep on listening to this event please listen to the stream drain event directly.'
163+
);
164+
}
165+
});
126166
}
127-
util.inherits(RedisClient, events.EventEmitter);
167+
util.inherits(RedisClient, EventEmitter);
168+
169+
RedisClient.connection_id = 0;
128170

129171
// Attention: the function name "create_stream" should not be changed, as other libraries need this to mock the stream (e.g. fakeredis)
130172
RedisClient.prototype.create_stream = function () {
@@ -238,19 +280,23 @@ RedisClient.prototype.unref = function () {
238280
};
239281

240282
RedisClient.prototype.warn = function (msg) {
241-
if (this.listeners('warning').length !== 0) {
242-
this.emit('warning', msg);
243-
} else {
244-
console.warn('node_redis:', msg);
245-
}
283+
var self = this;
284+
// Warn on the next tick. Otherwise no event listener can be added
285+
// for warnings that are emitted in the redis client constructor
286+
process.nextTick(function () {
287+
if (self.listeners('warning').length !== 0) {
288+
self.emit('warning', msg);
289+
} else {
290+
console.warn('node_redis:', msg);
291+
}
292+
});
246293
};
247294

248295
// Flush provided queues, erroring any items with a callback first
249296
RedisClient.prototype.flush_and_error = function (error, queue_names) {
250-
var command_obj;
251297
queue_names = queue_names || ['offline_queue', 'command_queue'];
252298
for (var i = 0; i < queue_names.length; i++) {
253-
while (command_obj = this[queue_names[i]].shift()) {
299+
for (var command_obj = this[queue_names[i]].shift(); command_obj; command_obj = this[queue_names[i]].shift()) {
254300
if (typeof command_obj.callback === 'function') {
255301
error.command = command_obj.command.toUpperCase();
256302
command_obj.callback(error);
@@ -419,9 +465,7 @@ RedisClient.prototype.ready_check = function () {
419465
};
420466

421467
RedisClient.prototype.send_offline_queue = function () {
422-
var command_obj;
423-
424-
while (command_obj = this.offline_queue.shift()) {
468+
for (var command_obj = this.offline_queue.shift(); command_obj; command_obj = this.offline_queue.shift()) {
425469
debug('Sending offline command: ' + command_obj.command);
426470
this.send_command(command_obj.command, command_obj.args, command_obj.callback);
427471
}
@@ -805,8 +849,7 @@ RedisClient.prototype.writeDefault = RedisClient.prototype.writeStrings = functi
805849
};
806850

807851
RedisClient.prototype.writeBuffers = function (data) {
808-
var command;
809-
while (command = this.pipeline_queue.shift()) {
852+
for (var command = this.pipeline_queue.shift(); command; command = this.pipeline_queue.shift()) {
810853
this.stream.write(command);
811854
}
812855
this.should_buffer = !this.stream.write(data);

test/commands/blpop.spec.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var assert = require("assert");
44
var config = require("../lib/config");
55
var helper = require("../helper");
66
var redis = config.redis;
7+
var intercept = require('intercept-stdout');
78

89
describe("The 'blpop' method", function () {
910

@@ -23,7 +24,14 @@ describe("The 'blpop' method", function () {
2324
it('pops value immediately if list contains values', function (done) {
2425
bclient = redis.createClient.apply(redis.createClient, args);
2526
redis.debug_mode = true;
27+
var text = '';
28+
var unhookIntercept = intercept(function(data) {
29+
text += data;
30+
return '';
31+
});
2632
client.rpush("blocking list", "initial value", helper.isNumber(1));
33+
unhookIntercept();
34+
assert(/^Send 127\.0\.0\.1:6379 id [0-9]+: \*3\r\n\$5\r\nrpush\r\n\$13\r\nblocking list\r\n\$13\r\ninitial value\r\n\n$/.test(text));
2735
redis.debug_mode = false;
2836
bclient.blpop("blocking list", 0, function (err, value) {
2937
assert.strictEqual(value[0], "blocking list");

test/commands/get.spec.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ describe("The 'get' method", function () {
6868
});
6969

7070
it("gets the value correctly", function (done) {
71-
client.GET(key, redis.print); // Use the utility function to print the result
7271
client.GET(key, function (err, res) {
7372
helper.isString(value)(err, res);
7473
done(err);

test/commands/getset.spec.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ describe("The 'getset' method", function () {
3333
});
3434

3535
it("reports an error", function (done) {
36-
client.GET(key, redis.print); // Use the utility function to print the error
3736
client.get(key, function (err, res) {
3837
assert(err.message.match(/The connection has already been closed/));
3938
done();

test/connection.spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var assert = require("assert");
44
var config = require("./lib/config");
55
var helper = require('./helper');
66
var redis = config.redis;
7+
var intercept = require('intercept-stdout');
78

89
describe("connection tests", function () {
910
helper.allTests(function(parser, ip, args) {
@@ -91,6 +92,7 @@ describe("connection tests", function () {
9192

9293
client.on("reconnecting", function (params) {
9394
client.end(true);
95+
assert.strictEqual(params.times_connected, 1);
9496
setTimeout(done, 100);
9597
});
9698
});

test/lib/stunnel-process.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22

33
// helper to start and stop the stunnel process.
44
var spawn = require('child_process').spawn;
5-
var EventEmitter = require('events').EventEmitter;
5+
var EventEmitter = require('events');
66
var fs = require('fs');
77
var path = require('path');
88
var util = require('util');
99

10+
// Newer Node.js versions > 0.10 return the EventEmitter right away and using .EventEmitter was deprecated
11+
if (typeof EventEmitter !== 'function') {
12+
EventEmitter = EventEmitter.EventEmitter;
13+
}
14+
1015
function once(cb) {
1116
var called = false;
1217
return function() {

test/node_redis.spec.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,18 @@ describe("The node_redis client", function () {
384384

385385
describe('idle', function () {
386386
it('emits idle as soon as there are no outstanding commands', function (done) {
387+
var end = helper.callFuncAfter(done, 2);
388+
client.on('warning', function (msg) {
389+
assert.strictEqual(
390+
msg,
391+
'The idle event listener is deprecated and will likely be removed in v.3.0.0.\n' +
392+
'If you rely on this feature please open a new ticket in node_redis with your use case'
393+
);
394+
end();
395+
});
387396
client.on('idle', function onIdle () {
388397
client.removeListener("idle", onIdle);
389-
client.get('foo', helper.isString('bar', done));
398+
client.get('foo', helper.isString('bar', end));
390399
});
391400
client.set('foo', 'bar');
392401
});
@@ -614,9 +623,17 @@ describe("The node_redis client", function () {
614623
parser: parser,
615624
no_ready_check: true
616625
});
617-
var end = helper.callFuncAfter(done, 2);
626+
var end = helper.callFuncAfter(done, 3);
618627
client.set('foo', 'bar');
619628
client.get('foo', end);
629+
client.on('warning', function (msg) {
630+
assert.strictEqual(
631+
msg,
632+
'The drain event listener is deprecated and will be removed in v.3.0.0.\n' +
633+
'If you want to keep on listening to this event please listen to the stream drain event directly.'
634+
);
635+
end();
636+
});
620637
client.on('drain', function() {
621638
assert(client.offline_queue.length === 0);
622639
end();
@@ -673,6 +690,9 @@ describe("The node_redis client", function () {
673690
client.on('reconnecting', function(params) {
674691
i++;
675692
assert.equal(params.attempt, i);
693+
assert.strictEqual(params.times_connected, 0);
694+
assert(params.error instanceof Error);
695+
assert(typeof params.total_retry_time === 'number');
676696
assert.strictEqual(client.offline_queue.length, 2);
677697
});
678698

@@ -706,10 +726,6 @@ describe("The node_redis client", function () {
706726
helper.killConnection(client);
707727
});
708728

709-
client.on("reconnecting", function (params) {
710-
assert.equal(client.command_queue.length, 15);
711-
});
712-
713729
client.on('error', function(err) {
714730
if (/uncertain state/.test(err.message)) {
715731
assert.equal(client.command_queue.length, 0);
@@ -787,10 +803,6 @@ describe("The node_redis client", function () {
787803
helper.killConnection(client);
788804
});
789805

790-
client.on("reconnecting", function (params) {
791-
assert.equal(client.command_queue.length, 15);
792-
});
793-
794806
client.on('error', function(err) {
795807
if (err.code === 'UNCERTAIN_STATE') {
796808
assert.equal(client.command_queue.length, 0);

test/utils.spec.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var assert = require('assert');
44
var Queue = require('double-ended-queue');
55
var utils = require('../lib/utils');
6+
var intercept = require('intercept-stdout');
67

78
describe('utils.js', function () {
89

@@ -40,6 +41,30 @@ describe('utils.js', function () {
4041
});
4142
});
4243

44+
describe('print helper', function () {
45+
it('callback with reply', function () {
46+
var text = '';
47+
var unhookIntercept = intercept(function(data) {
48+
text += data;
49+
return '';
50+
});
51+
utils.print(null, 'abc');
52+
unhookIntercept();
53+
assert.strictEqual(text, 'Reply: abc\n');
54+
});
55+
56+
it('callback with error', function () {
57+
var text = '';
58+
var unhookIntercept = intercept(function(data) {
59+
text += data;
60+
return '';
61+
});
62+
utils.print(new Error('Wonderful exception'));
63+
unhookIntercept();
64+
assert.strictEqual(text, 'Error: Wonderful exception\n');
65+
});
66+
});
67+
4368
describe('reply_in_order', function () {
4469

4570
var err_count = 0;

0 commit comments

Comments
 (0)