redis 2.6.4 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +259 -134
- package/changelog.md +49 -13
- package/index.js +24 -8
- package/lib/commands.js +14 -6
- package/lib/createClient.js +3 -2
- package/lib/customErrors.js +19 -6
- package/lib/extendedApi.js +3 -2
- package/lib/individualCommands.js +8 -8
- package/lib/utils.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -6,7 +6,8 @@ redis - a node.js redis client
|
|
|
6
6
|
[](https://ci.appveyor.com/project/BridgeAR/node-redis/branch/master)
|
|
7
7
|
[](https://gitter.im/NodeRedis/node_redis?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
8
8
|
|
|
9
|
-
This is a complete and feature rich Redis client for node.js. __It supports all
|
|
9
|
+
This is a complete and feature rich Redis client for node.js. __It supports all
|
|
10
|
+
Redis commands__ and focuses on high performance.
|
|
10
11
|
|
|
11
12
|
Install with:
|
|
12
13
|
|
|
@@ -48,13 +49,16 @@ This will display:
|
|
|
48
49
|
1: hashtest 2
|
|
49
50
|
mjr:~/work/node_redis (master)$
|
|
50
51
|
|
|
51
|
-
Note that the API is entirely asynchronous. To get data back from the server,
|
|
52
|
-
From v.2.6 on the API supports camelCase and
|
|
53
|
-
|
|
52
|
+
Note that the API is entirely asynchronous. To get data back from the server,
|
|
53
|
+
you'll need to use a callback. From v.2.6 on the API supports camelCase and
|
|
54
|
+
snake_case and all options / variables / events etc. can be used either way. It
|
|
55
|
+
is recommended to use camelCase as this is the default for the Node.js
|
|
56
|
+
landscape.
|
|
54
57
|
|
|
55
58
|
### Promises
|
|
56
59
|
|
|
57
|
-
You can also use node_redis with promises by promisifying node_redis with
|
|
60
|
+
You can also use node_redis with promises by promisifying node_redis with
|
|
61
|
+
[bluebird](https://github.com/petkaantonov/bluebird) as in:
|
|
58
62
|
|
|
59
63
|
```js
|
|
60
64
|
var redis = require('redis');
|
|
@@ -100,7 +104,8 @@ client.set("some key", "some val");
|
|
|
100
104
|
client.set(["some other key", "some val"]);
|
|
101
105
|
```
|
|
102
106
|
|
|
103
|
-
If the key is missing, reply will be null. Only if the [Redis Command
|
|
107
|
+
If the key is missing, reply will be null. Only if the [Redis Command
|
|
108
|
+
Reference](http://redis.io/commands) states something else it will not be null.
|
|
104
109
|
|
|
105
110
|
```js
|
|
106
111
|
client.get("missingkey", function(err, reply) {
|
|
@@ -111,8 +116,24 @@ client.get("missingkey", function(err, reply) {
|
|
|
111
116
|
|
|
112
117
|
For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands)
|
|
113
118
|
|
|
114
|
-
Minimal parsing is done on the replies. Commands that return a integer return
|
|
115
|
-
|
|
119
|
+
Minimal parsing is done on the replies. Commands that return a integer return
|
|
120
|
+
JavaScript Numbers, arrays return JavaScript Array. `HGETALL` returns an Object
|
|
121
|
+
keyed by the hash keys. All strings will either be returned as string or as
|
|
122
|
+
buffer depending on your setting. Please be aware that sending null, undefined
|
|
123
|
+
and Boolean values will result in the value coerced to a string!
|
|
124
|
+
|
|
125
|
+
# Redis Commands
|
|
126
|
+
|
|
127
|
+
This library is a 1 to 1 mapping to [Redis commands](https://redis.io/commands).
|
|
128
|
+
It is not a cache library so please refer to Redis commands page for full usage
|
|
129
|
+
details.
|
|
130
|
+
|
|
131
|
+
Example setting key to auto expire using [SET command](https://redis.io/commands/set)
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
// this key will expire after 10 seconds
|
|
135
|
+
client.set('key', 'value!', 'EX', 10);
|
|
136
|
+
```
|
|
116
137
|
|
|
117
138
|
# API
|
|
118
139
|
|
|
@@ -122,8 +143,9 @@ Please be aware that sending null, undefined and Boolean values will result in t
|
|
|
122
143
|
|
|
123
144
|
### "ready"
|
|
124
145
|
|
|
125
|
-
`client` will emit `ready` once a connection is established. Commands issued
|
|
126
|
-
then replayed just before this event is
|
|
146
|
+
`client` will emit `ready` once a connection is established. Commands issued
|
|
147
|
+
before the `ready` event are queued, then replayed just before this event is
|
|
148
|
+
emitted.
|
|
127
149
|
|
|
128
150
|
### "connect"
|
|
129
151
|
|
|
@@ -131,13 +153,16 @@ then replayed just before this event is emitted.
|
|
|
131
153
|
|
|
132
154
|
### "reconnecting"
|
|
133
155
|
|
|
134
|
-
`client` will emit `reconnecting` when trying to reconnect to the Redis server
|
|
135
|
-
are passed an object containing `delay`
|
|
156
|
+
`client` will emit `reconnecting` when trying to reconnect to the Redis server
|
|
157
|
+
after losing the connection. Listeners are passed an object containing `delay`
|
|
158
|
+
(in ms) and `attempt` (the attempt #) attributes.
|
|
136
159
|
|
|
137
160
|
### "error"
|
|
138
161
|
|
|
139
|
-
`client` will emit `error` when encountering an error connecting to the Redis
|
|
140
|
-
|
|
162
|
+
`client` will emit `error` when encountering an error connecting to the Redis
|
|
163
|
+
server or when any other in node_redis occurs. If you use a command without
|
|
164
|
+
callback and encounter a ReplyError it is going to be emitted to the error
|
|
165
|
+
listener.
|
|
141
166
|
|
|
142
167
|
So please attach the error listener to node_redis.
|
|
143
168
|
|
|
@@ -147,33 +172,41 @@ So please attach the error listener to node_redis.
|
|
|
147
172
|
|
|
148
173
|
### "drain" (deprecated)
|
|
149
174
|
|
|
150
|
-
`client` will emit `drain` when the TCP connection to the Redis server has been
|
|
151
|
-
writable. This event can be used to stream commands in to
|
|
175
|
+
`client` will emit `drain` when the TCP connection to the Redis server has been
|
|
176
|
+
buffering, but is now writable. This event can be used to stream commands in to
|
|
177
|
+
Redis and adapt to backpressure.
|
|
152
178
|
|
|
153
|
-
If the stream is buffering `client.should_buffer` is set to true. Otherwise the
|
|
154
|
-
That way you can decide when to reduce your
|
|
179
|
+
If the stream is buffering `client.should_buffer` is set to true. Otherwise the
|
|
180
|
+
variable is always set to false. That way you can decide when to reduce your
|
|
181
|
+
send rate and resume sending commands when you get `drain`.
|
|
155
182
|
|
|
156
|
-
You can also check the return value of each command as it will also return the
|
|
157
|
-
If false is returned the stream had to
|
|
183
|
+
You can also check the return value of each command as it will also return the
|
|
184
|
+
backpressure indicator (deprecated). If false is returned the stream had to
|
|
185
|
+
buffer.
|
|
158
186
|
|
|
159
187
|
### "warning"
|
|
160
188
|
|
|
161
|
-
`client` will emit `warning` when password was set but none is needed and if a
|
|
189
|
+
`client` will emit `warning` when password was set but none is needed and if a
|
|
190
|
+
deprecated option / function / similar is used.
|
|
162
191
|
|
|
163
192
|
### "idle" (deprecated)
|
|
164
193
|
|
|
165
|
-
`client` will emit `idle` when there are no outstanding commands that are
|
|
194
|
+
`client` will emit `idle` when there are no outstanding commands that are
|
|
195
|
+
awaiting a response.
|
|
166
196
|
|
|
167
197
|
## redis.createClient()
|
|
168
|
-
If you have `redis-server` running on the same machine as node, then the
|
|
169
|
-
port and host are probably fine and you don't need to supply any
|
|
198
|
+
If you have `redis-server` running on the same machine as node, then the
|
|
199
|
+
defaults for port and host are probably fine and you don't need to supply any
|
|
200
|
+
arguments. `createClient()` returns a `RedisClient` object. Otherwise,
|
|
201
|
+
`createClient()` accepts these arguments:
|
|
170
202
|
|
|
171
203
|
* `redis.createClient([options])`
|
|
172
204
|
* `redis.createClient(unix_socket[, options])`
|
|
173
205
|
* `redis.createClient(redis_url[, options])`
|
|
174
206
|
* `redis.createClient(port[, host][, options])`
|
|
175
207
|
|
|
176
|
-
__Tip:__ If the Redis server runs on the same machine as the client consider
|
|
208
|
+
__Tip:__ If the Redis server runs on the same machine as the client consider
|
|
209
|
+
using unix sockets if possible to increase throughput.
|
|
177
210
|
|
|
178
211
|
#### `options` object properties
|
|
179
212
|
| Property | Default | Description |
|
|
@@ -197,7 +230,7 @@ __Tip:__ If the Redis server runs on the same machine as the client consider usi
|
|
|
197
230
|
| db | null | If set, client will run Redis `select` command on connect. |
|
|
198
231
|
| 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 on how to use the family type. |
|
|
199
232
|
| disable_resubscribing | false | If set to `true`, a client won't resubscribe after disconnecting. |
|
|
200
|
-
| rename_commands | null | Passing an object with renamed commands to use instead of the original functions. See the [Redis security topics](http://redis.io/topics/security) for more info. |
|
|
233
|
+
| rename_commands | null | Passing an object with renamed commands to use instead of the original functions. For example, if you renamed the command KEYS to "DO-NOT-USE" then the rename_commands object would be: `{ KEYS : "DO-NOT-USE" }` . See the [Redis security topics](http://redis.io/topics/security) for more info. |
|
|
201
234
|
| tls | null | An object containing options to pass to [tls.connect](http://nodejs.org/api/tls.html#tls_tls_connect_port_host_options_callback) to set up a TLS connection to Redis (if, for example, it is set up to be accessible via a tunnel). |
|
|
202
235
|
| prefix | null | A string used to prefix all used keys (e.g. `namespace:test`). Please be aware that the `keys` command will not be prefixed. The `keys` command has a "pattern" as argument and no key and it would be impossible to determine the existing keys in Redis if this would be prefixed. |
|
|
203
236
|
| retry_strategy | function | A function that receives an options object as parameter including the retry `attempt`, the `total_retry_time` indicating how much time passed since the last time connected, the `error` why the connection was lost and the number of `times_connected` in total. If you return a number from this function, the retry will happen exactly after that time in milliseconds. If you return a non-number, no further retry will happen and all offline commands are flushed with errors. Return an error to return that specific error to all offline commands. Example below. |
|
|
@@ -221,18 +254,21 @@ client.quit();
|
|
|
221
254
|
```
|
|
222
255
|
|
|
223
256
|
retry_strategy example
|
|
257
|
+
|
|
224
258
|
```js
|
|
225
259
|
var client = redis.createClient({
|
|
226
260
|
retry_strategy: function (options) {
|
|
227
261
|
if (options.error && options.error.code === 'ECONNREFUSED') {
|
|
228
|
-
// End reconnecting on a specific error and flush all commands with
|
|
262
|
+
// End reconnecting on a specific error and flush all commands with
|
|
263
|
+
// a individual error
|
|
229
264
|
return new Error('The server refused the connection');
|
|
230
265
|
}
|
|
231
266
|
if (options.total_retry_time > 1000 * 60 * 60) {
|
|
232
|
-
// End reconnecting after a specific timeout and flush all commands
|
|
267
|
+
// End reconnecting after a specific timeout and flush all commands
|
|
268
|
+
// with a individual error
|
|
233
269
|
return new Error('Retry time exhausted');
|
|
234
270
|
}
|
|
235
|
-
if (options.
|
|
271
|
+
if (options.attempt > 10) {
|
|
236
272
|
// End reconnecting with built in error
|
|
237
273
|
return undefined;
|
|
238
274
|
}
|
|
@@ -244,11 +280,12 @@ var client = redis.createClient({
|
|
|
244
280
|
|
|
245
281
|
## client.auth(password[, callback])
|
|
246
282
|
|
|
247
|
-
When connecting to a Redis server that requires authentication, the `AUTH`
|
|
248
|
-
first command after connecting. This can be tricky
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
`
|
|
283
|
+
When connecting to a Redis server that requires authentication, the `AUTH`
|
|
284
|
+
command must be sent as the first command after connecting. This can be tricky
|
|
285
|
+
to coordinate with reconnections, the ready check, etc. To make this easier,
|
|
286
|
+
`client.auth()` stashes `password` and will send it after each connection,
|
|
287
|
+
including reconnections. `callback` is invoked only once, after the response to
|
|
288
|
+
the very first `AUTH` command sent.
|
|
252
289
|
NOTE: Your call to `client.auth()` should not be inside the ready handler. If
|
|
253
290
|
you are doing this wrong, `client` will emit an error that looks
|
|
254
291
|
something like this `Error: Ready check failed: ERR operation not permitted`.
|
|
@@ -257,25 +294,34 @@ something like this `Error: Ready check failed: ERR operation not permitted`.
|
|
|
257
294
|
|
|
258
295
|
### stream
|
|
259
296
|
|
|
260
|
-
The client exposed the used [stream](https://nodejs.org/api/stream.html) in
|
|
261
|
-
|
|
297
|
+
The client exposed the used [stream](https://nodejs.org/api/stream.html) in
|
|
298
|
+
`client.stream` and if the stream or client had to
|
|
299
|
+
[buffer](https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback)
|
|
300
|
+
the command in `client.should_buffer`. In combination this can be used to
|
|
301
|
+
implement backpressure by checking the buffer state before sending a command and
|
|
302
|
+
listening to the stream
|
|
303
|
+
[drain](https://nodejs.org/api/stream.html#stream_event_drain) event.
|
|
262
304
|
|
|
263
305
|
## client.quit()
|
|
264
306
|
|
|
265
|
-
This sends the quit command to the redis server and ends cleanly right after all
|
|
266
|
-
If this is called while reconnecting
|
|
267
|
-
|
|
307
|
+
This sends the quit command to the redis server and ends cleanly right after all
|
|
308
|
+
running commands were properly handled. If this is called while reconnecting
|
|
309
|
+
(and therefore no connection to the redis server exists) it is going to end the
|
|
310
|
+
connection right away instead of resulting in further reconnections! All offline
|
|
311
|
+
commands are going to be flushed with an error in that case.
|
|
268
312
|
|
|
269
313
|
## client.end(flush)
|
|
270
314
|
|
|
271
|
-
Forcibly close the connection to the Redis server. Note that this does not wait
|
|
272
|
-
If you want to exit cleanly, call
|
|
315
|
+
Forcibly close the connection to the Redis server. Note that this does not wait
|
|
316
|
+
until all replies have been parsed. If you want to exit cleanly, call
|
|
317
|
+
`client.quit()` as mentioned above.
|
|
273
318
|
|
|
274
|
-
You should set flush to true, if you are not absolutely sure you do not care
|
|
275
|
-
If you set flush to false all still running commands
|
|
319
|
+
You should set flush to true, if you are not absolutely sure you do not care
|
|
320
|
+
about any other commands. If you set flush to false all still running commands
|
|
321
|
+
will silently fail.
|
|
276
322
|
|
|
277
|
-
This example closes the connection to the Redis server before the replies have
|
|
278
|
-
want to do this:
|
|
323
|
+
This example closes the connection to the Redis server before the replies have
|
|
324
|
+
been read. You probably don't want to do this:
|
|
279
325
|
|
|
280
326
|
```js
|
|
281
327
|
var redis = require("redis"),
|
|
@@ -296,10 +342,19 @@ client.get("foo_rand000000000000", function (err, reply) {
|
|
|
296
342
|
|
|
297
343
|
## Error handling (>= v.2.6)
|
|
298
344
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
345
|
+
Currently the following error subclasses exist:
|
|
346
|
+
|
|
347
|
+
* `RedisError`: _All errors_ returned by the client
|
|
348
|
+
* `ReplyError` subclass of `RedisError`: All errors returned by __Redis__ itself
|
|
349
|
+
* `AbortError` subclass of `RedisError`: All commands that could not finish due
|
|
350
|
+
to what ever reason
|
|
351
|
+
* `ParserError` subclass of `RedisError`: Returned in case of a parser error
|
|
352
|
+
(this should not happen)
|
|
353
|
+
* `AggregateError` subclass of `AbortError`: Emitted in case multiple unresolved
|
|
354
|
+
commands without callback got rejected in debug_mode instead of lots of
|
|
355
|
+
`AbortError`s.
|
|
356
|
+
|
|
357
|
+
All error classes are exported by the module.
|
|
303
358
|
|
|
304
359
|
Example:
|
|
305
360
|
```js
|
|
@@ -311,10 +366,11 @@ client.on('error', function (err) {
|
|
|
311
366
|
assert(err instanceof Error);
|
|
312
367
|
assert(err instanceof redis.AbortError);
|
|
313
368
|
assert(err instanceof redis.AggregateError);
|
|
314
|
-
|
|
369
|
+
// The set and get get aggregated in here
|
|
370
|
+
assert.strictEqual(err.errors.length, 2);
|
|
315
371
|
assert.strictEqual(err.code, 'NR_CLOSED');
|
|
316
372
|
});
|
|
317
|
-
client.set('foo', 123, 'bar', function (err, res) { //
|
|
373
|
+
client.set('foo', 123, 'bar', function (err, res) { // Too many arguments
|
|
318
374
|
assert(err instanceof redis.ReplyError); // => true
|
|
319
375
|
assert.strictEqual(err.command, 'SET');
|
|
320
376
|
assert.deepStrictEqual(err.args, ['foo', 123, 'bar']);
|
|
@@ -323,7 +379,8 @@ client.set('foo', 123, 'bar', function (err, res) { // To many arguments
|
|
|
323
379
|
client.set('foo', 'bar');
|
|
324
380
|
client.get('foo');
|
|
325
381
|
process.nextTick(function () {
|
|
326
|
-
|
|
382
|
+
// Force closing the connection while the command did not yet return
|
|
383
|
+
client.end(true);
|
|
327
384
|
redis.debug_mode = false;
|
|
328
385
|
});
|
|
329
386
|
});
|
|
@@ -332,25 +389,33 @@ client.set('foo', 123, 'bar', function (err, res) { // To many arguments
|
|
|
332
389
|
|
|
333
390
|
Every `ReplyError` contains the `command` name in all-caps and the arguments (`args`).
|
|
334
391
|
|
|
335
|
-
If node_redis emits a library error because of another error, the triggering
|
|
392
|
+
If node_redis emits a library error because of another error, the triggering
|
|
393
|
+
error is added to the returned error as `origin` attribute.
|
|
336
394
|
|
|
337
395
|
___Error codes___
|
|
338
396
|
|
|
339
|
-
node_redis returns a `NR_CLOSED` error code if the clients connection dropped.
|
|
340
|
-
|
|
397
|
+
node_redis returns a `NR_CLOSED` error code if the clients connection dropped.
|
|
398
|
+
If a command unresolved command got rejected a `UNCERTAIN_STATE` code is
|
|
399
|
+
returned. A `CONNECTION_BROKEN` error code is used in case node_redis gives up
|
|
400
|
+
to reconnect.
|
|
341
401
|
|
|
342
402
|
## client.unref()
|
|
343
403
|
|
|
344
|
-
Call `unref()` on the underlying socket connection to the Redis server, allowing
|
|
404
|
+
Call `unref()` on the underlying socket connection to the Redis server, allowing
|
|
405
|
+
the program to exit once no more commands are pending.
|
|
345
406
|
|
|
346
|
-
This is an **experimental** feature, and only supports a subset of the Redis
|
|
407
|
+
This is an **experimental** feature, and only supports a subset of the Redis
|
|
408
|
+
protocol. Any commands where client state is saved on the Redis server, e.g.
|
|
409
|
+
`*SUBSCRIBE` or the blocking `BL*` commands will *NOT* work with `.unref()`.
|
|
347
410
|
|
|
348
411
|
```js
|
|
349
412
|
var redis = require("redis")
|
|
350
413
|
var client = redis.createClient()
|
|
351
414
|
|
|
352
415
|
/*
|
|
353
|
-
Calling unref() will allow this program to exit immediately after the get
|
|
416
|
+
Calling unref() will allow this program to exit immediately after the get
|
|
417
|
+
command finishes. Otherwise the client would hang as long as the
|
|
418
|
+
client-server connection is alive.
|
|
354
419
|
*/
|
|
355
420
|
client.unref()
|
|
356
421
|
client.get("foo", function (err, value){
|
|
@@ -361,13 +426,15 @@ client.get("foo", function (err, value){
|
|
|
361
426
|
|
|
362
427
|
## Friendlier hash commands
|
|
363
428
|
|
|
364
|
-
Most Redis commands take a single String or an Array of Strings as arguments,
|
|
365
|
-
|
|
429
|
+
Most Redis commands take a single String or an Array of Strings as arguments,
|
|
430
|
+
and replies are sent back as a single String or an Array of Strings. When
|
|
431
|
+
dealing with hash values, there are a couple of useful exceptions to this.
|
|
366
432
|
|
|
367
433
|
### client.hgetall(hash, callback)
|
|
368
434
|
|
|
369
|
-
The reply from an HGETALL command will be converted into a JavaScript Object by
|
|
370
|
-
with the responses using JavaScript
|
|
435
|
+
The reply from an HGETALL command will be converted into a JavaScript Object by
|
|
436
|
+
`node_redis`. That way you can interact with the responses using JavaScript
|
|
437
|
+
syntax.
|
|
371
438
|
|
|
372
439
|
Example:
|
|
373
440
|
|
|
@@ -395,7 +462,8 @@ client.HMSET(key2, {
|
|
|
395
462
|
});
|
|
396
463
|
```
|
|
397
464
|
|
|
398
|
-
The properties and values of this Object will be set as keys and values in the
|
|
465
|
+
The properties and values of this Object will be set as keys and values in the
|
|
466
|
+
Redis hash.
|
|
399
467
|
|
|
400
468
|
### client.hmset(hash, key1, val1, ... keyn, valn, [callback])
|
|
401
469
|
|
|
@@ -435,11 +503,13 @@ sub.on("message", function (channel, message) {
|
|
|
435
503
|
sub.subscribe("a nice channel");
|
|
436
504
|
```
|
|
437
505
|
|
|
438
|
-
When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into
|
|
439
|
-
At that point, only commands that modify the subscription
|
|
440
|
-
set
|
|
506
|
+
When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into
|
|
507
|
+
a "subscriber" mode. At that point, only commands that modify the subscription
|
|
508
|
+
set are valid and quit (and depending on the redis version ping as well). When
|
|
509
|
+
the subscription set is empty, the connection is put back into regular mode.
|
|
441
510
|
|
|
442
|
-
If you need to send regular commands to Redis while in subscriber mode, just
|
|
511
|
+
If you need to send regular commands to Redis while in subscriber mode, just
|
|
512
|
+
open another connection with a new client (hint: use `client.duplicate()`).
|
|
443
513
|
|
|
444
514
|
## Subscriber Events
|
|
445
515
|
|
|
@@ -452,47 +522,57 @@ Listeners are passed the channel name as `channel` and the message as `message`.
|
|
|
452
522
|
|
|
453
523
|
### "pmessage" (pattern, channel, message)
|
|
454
524
|
|
|
455
|
-
Client will emit `pmessage` for every message received that matches an active
|
|
456
|
-
Listeners are passed the original pattern used with
|
|
457
|
-
|
|
525
|
+
Client will emit `pmessage` for every message received that matches an active
|
|
526
|
+
subscription pattern. Listeners are passed the original pattern used with
|
|
527
|
+
`PSUBSCRIBE` as `pattern`, the sending channel name as `channel`, and the
|
|
528
|
+
message as `message`.
|
|
458
529
|
|
|
459
530
|
### "message_buffer" (channel, message)
|
|
460
531
|
|
|
461
|
-
This is the same as the `message` event with the exception, that it is always
|
|
462
|
-
If you listen to the `message` event at the same time as
|
|
532
|
+
This is the same as the `message` event with the exception, that it is always
|
|
533
|
+
going to emit a buffer. If you listen to the `message` event at the same time as
|
|
534
|
+
the `message_buffer`, it is always going to emit a string.
|
|
463
535
|
|
|
464
536
|
### "pmessage_buffer" (pattern, channel, message)
|
|
465
537
|
|
|
466
|
-
This is the same as the `pmessage` event with the exception, that it is always
|
|
467
|
-
If you listen to the `pmessage` event at the same time
|
|
538
|
+
This is the same as the `pmessage` event with the exception, that it is always
|
|
539
|
+
going to emit a buffer. If you listen to the `pmessage` event at the same time
|
|
540
|
+
as the `pmessage_buffer`, it is always going to emit a string.
|
|
468
541
|
|
|
469
542
|
### "subscribe" (channel, count)
|
|
470
543
|
|
|
471
|
-
Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are
|
|
472
|
-
channel name as `channel` and the new count of subscriptions for this
|
|
544
|
+
Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are
|
|
545
|
+
passed the channel name as `channel` and the new count of subscriptions for this
|
|
546
|
+
client as `count`.
|
|
473
547
|
|
|
474
548
|
### "psubscribe" (pattern, count)
|
|
475
549
|
|
|
476
|
-
Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners
|
|
477
|
-
original pattern as `pattern`, and the new count of subscriptions
|
|
550
|
+
Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners
|
|
551
|
+
are passed the original pattern as `pattern`, and the new count of subscriptions
|
|
552
|
+
for this client as `count`.
|
|
478
553
|
|
|
479
554
|
### "unsubscribe" (channel, count)
|
|
480
555
|
|
|
481
|
-
Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners
|
|
482
|
-
channel name as `channel` and the new count of subscriptions for
|
|
483
|
-
`count` is 0, this client has left subscriber mode
|
|
556
|
+
Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners
|
|
557
|
+
are passed the channel name as `channel` and the new count of subscriptions for
|
|
558
|
+
this client as `count`. When `count` is 0, this client has left subscriber mode
|
|
559
|
+
and no more subscriber events will be emitted.
|
|
484
560
|
|
|
485
561
|
### "punsubscribe" (pattern, count)
|
|
486
562
|
|
|
487
|
-
Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command.
|
|
488
|
-
channel name as `channel` and the new count of
|
|
489
|
-
`count` is 0, this client has
|
|
563
|
+
Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command.
|
|
564
|
+
Listeners are passed the channel name as `channel` and the new count of
|
|
565
|
+
subscriptions for this client as `count`. When `count` is 0, this client has
|
|
566
|
+
left subscriber mode and no more subscriber events will be emitted.
|
|
490
567
|
|
|
491
568
|
## client.multi([commands])
|
|
492
569
|
|
|
493
|
-
`MULTI` commands are queued up until an `EXEC` is issued, and then all commands
|
|
494
|
-
Redis. The interface in `node_redis` is to return an
|
|
495
|
-
|
|
570
|
+
`MULTI` commands are queued up until an `EXEC` is issued, and then all commands
|
|
571
|
+
are run atomically by Redis. The interface in `node_redis` is to return an
|
|
572
|
+
individual `Multi` object by calling `client.multi()`. If any command fails to
|
|
573
|
+
queue, all commands are rolled back and none is going to be executed (For
|
|
574
|
+
further information look at
|
|
575
|
+
[transactions](http://redis.io/topics/transactions)).
|
|
496
576
|
|
|
497
577
|
```js
|
|
498
578
|
var redis = require("./index"),
|
|
@@ -526,15 +606,20 @@ client.multi()
|
|
|
526
606
|
|
|
527
607
|
### Multi.exec([callback])
|
|
528
608
|
|
|
529
|
-
`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects
|
|
530
|
-
same command methods as `client` objects do. Commands are
|
|
531
|
-
until `Multi.exec()` is invoked.
|
|
609
|
+
`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects
|
|
610
|
+
share all of the same command methods as `client` objects do. Commands are
|
|
611
|
+
queued up inside the `Multi` object until `Multi.exec()` is invoked.
|
|
532
612
|
|
|
533
|
-
If your code contains an syntax error an EXECABORT error is going to be thrown
|
|
534
|
-
|
|
613
|
+
If your code contains an syntax error an EXECABORT error is going to be thrown
|
|
614
|
+
and all commands are going to be aborted. That error contains a `.errors`
|
|
615
|
+
property that contains the concrete errors.
|
|
616
|
+
If all commands were queued successfully and an error is thrown by redis while
|
|
617
|
+
processing the commands that error is going to be returned in the result array!
|
|
618
|
+
No other command is going to be aborted though than the onces failing.
|
|
535
619
|
|
|
536
|
-
You can either chain together `MULTI` commands as in the above example, or you
|
|
537
|
-
commands while still sending regular client command as in
|
|
620
|
+
You can either chain together `MULTI` commands as in the above example, or you
|
|
621
|
+
can queue individual commands while still sending regular client command as in
|
|
622
|
+
this example:
|
|
538
623
|
|
|
539
624
|
```js
|
|
540
625
|
var redis = require("redis"),
|
|
@@ -554,8 +639,8 @@ multi.exec(function (err, replies) {
|
|
|
554
639
|
});
|
|
555
640
|
```
|
|
556
641
|
|
|
557
|
-
In addition to adding commands to the `MULTI` queue individually, you can also
|
|
558
|
-
of commands and arguments to the constructor:
|
|
642
|
+
In addition to adding commands to the `MULTI` queue individually, you can also
|
|
643
|
+
pass an array of commands and arguments to the constructor:
|
|
559
644
|
|
|
560
645
|
```js
|
|
561
646
|
var redis = require("redis"),
|
|
@@ -572,26 +657,36 @@ client.multi([
|
|
|
572
657
|
|
|
573
658
|
### Multi.exec_atomic([callback])
|
|
574
659
|
|
|
575
|
-
Identical to Multi.exec but with the difference that executing a single command
|
|
660
|
+
Identical to Multi.exec but with the difference that executing a single command
|
|
661
|
+
will not use transactions.
|
|
576
662
|
|
|
577
663
|
## client.batch([commands])
|
|
578
664
|
|
|
579
|
-
Identical to .multi without transactions. This is recommended if you want to
|
|
665
|
+
Identical to .multi without transactions. This is recommended if you want to
|
|
666
|
+
execute many commands at once but don't have to rely on transactions.
|
|
580
667
|
|
|
581
|
-
`BATCH` commands are queued up until an `EXEC` is issued, and then all commands
|
|
582
|
-
Redis. The interface in `node_redis` is to return an
|
|
583
|
-
|
|
584
|
-
|
|
668
|
+
`BATCH` commands are queued up until an `EXEC` is issued, and then all commands
|
|
669
|
+
are run atomically by Redis. The interface in `node_redis` is to return an
|
|
670
|
+
individual `Batch` object by calling `client.batch()`. The only difference
|
|
671
|
+
between .batch and .multi is that no transaction is going to be used.
|
|
672
|
+
Be aware that the errors are - just like in multi statements - in the result.
|
|
673
|
+
Otherwise both, errors and results could be returned at the same time.
|
|
585
674
|
|
|
586
|
-
If you fire many commands at once this is going to boost the execution speed
|
|
675
|
+
If you fire many commands at once this is going to boost the execution speed
|
|
676
|
+
significantly compared to firing the same commands in a loop without waiting for
|
|
677
|
+
the result! See the benchmarks for further comparison. Please remember that all
|
|
678
|
+
commands are kept in memory until they are fired.
|
|
587
679
|
|
|
588
680
|
## Monitor mode
|
|
589
681
|
|
|
590
|
-
Redis supports the `MONITOR` command, which lets you see all commands received
|
|
591
|
-
across all client connections, including from other client
|
|
682
|
+
Redis supports the `MONITOR` command, which lets you see all commands received
|
|
683
|
+
by the Redis server across all client connections, including from other client
|
|
684
|
+
libraries and other computers.
|
|
592
685
|
|
|
593
|
-
A `monitor` event is going to be emitted for every command fired from any client
|
|
594
|
-
|
|
686
|
+
A `monitor` event is going to be emitted for every command fired from any client
|
|
687
|
+
connected to the server including the monitoring client itself. The callback for
|
|
688
|
+
the `monitor` event takes a timestamp from the Redis server, an array of command
|
|
689
|
+
arguments and the raw monitoring string.
|
|
595
690
|
|
|
596
691
|
Example:
|
|
597
692
|
|
|
@@ -613,10 +708,11 @@ Some other things you might like to know about.
|
|
|
613
708
|
|
|
614
709
|
## client.server_info
|
|
615
710
|
|
|
616
|
-
After the ready probe completes, the results from the INFO command are saved in
|
|
617
|
-
object.
|
|
711
|
+
After the ready probe completes, the results from the INFO command are saved in
|
|
712
|
+
the `client.server_info` object.
|
|
618
713
|
|
|
619
|
-
The `versions` key contains an array of the elements of the version string for
|
|
714
|
+
The `versions` key contains an array of the elements of the version string for
|
|
715
|
+
easy comparison.
|
|
620
716
|
|
|
621
717
|
> client.server_info.redis_version
|
|
622
718
|
'2.3.0'
|
|
@@ -655,12 +751,15 @@ the second word as first parameter:
|
|
|
655
751
|
|
|
656
752
|
## client.duplicate([options][, callback])
|
|
657
753
|
|
|
658
|
-
Duplicate all current options and return a new redisClient instance. All options
|
|
659
|
-
|
|
754
|
+
Duplicate all current options and return a new redisClient instance. All options
|
|
755
|
+
passed to the duplicate function are going to replace the original option. If
|
|
756
|
+
you pass a callback, duplicate is going to wait until the client is ready and
|
|
757
|
+
returns it in the callback. If an error occurs in the meanwhile, that is going
|
|
758
|
+
to return an error instead in the callback.
|
|
660
759
|
|
|
661
|
-
One example of when to use duplicate() would be to
|
|
760
|
+
One example of when to use duplicate() would be to accommodate the connection-
|
|
662
761
|
blocking redis commands BRPOP, BLPOP, and BRPOPLPUSH. If these commands
|
|
663
|
-
are used on the same redisClient instance as non-blocking commands, the
|
|
762
|
+
are used on the same redisClient instance as non-blocking commands, the
|
|
664
763
|
non-blocking ones may be queued up until after the blocking ones finish.
|
|
665
764
|
|
|
666
765
|
var Redis=require('redis');
|
|
@@ -681,17 +780,25 @@ non-blocking ones may be queued up until after the blocking ones finish.
|
|
|
681
780
|
};
|
|
682
781
|
get();
|
|
683
782
|
brpop();
|
|
684
|
-
|
|
685
|
-
Another reason to use duplicate() is when multiple DBs on the same server are
|
|
783
|
+
|
|
784
|
+
Another reason to use duplicate() is when multiple DBs on the same server are
|
|
686
785
|
accessed via the redis SELECT command. Each DB could use its own connection.
|
|
687
|
-
|
|
786
|
+
|
|
688
787
|
## client.send_command(command_name[, [args][, callback]])
|
|
689
788
|
|
|
690
|
-
All Redis commands have been added to the `client` object. However, if new
|
|
691
|
-
|
|
692
|
-
|
|
789
|
+
All Redis commands have been added to the `client` object. However, if new
|
|
790
|
+
commands are introduced before this library is updated or if you want to add
|
|
791
|
+
individual commands you can use `send_command()` to send arbitrary commands to
|
|
792
|
+
Redis.
|
|
693
793
|
|
|
694
|
-
All commands are sent as multi-bulk commands. `args` can either be an Array of
|
|
794
|
+
All commands are sent as multi-bulk commands. `args` can either be an Array of
|
|
795
|
+
arguments, or omitted / set to undefined.
|
|
796
|
+
|
|
797
|
+
## client.add_command(command_name)
|
|
798
|
+
|
|
799
|
+
Calling add_command will add a new command to the prototype. The exact command
|
|
800
|
+
name will be used when calling using this new command. Using arbitrary arguments
|
|
801
|
+
is possible as with any other command.
|
|
695
802
|
|
|
696
803
|
## client.connected
|
|
697
804
|
|
|
@@ -699,19 +806,23 @@ Boolean tracking the state of the connection to the Redis server.
|
|
|
699
806
|
|
|
700
807
|
## client.command_queue_length
|
|
701
808
|
|
|
702
|
-
The number of commands that have been sent to the Redis server but not yet
|
|
703
|
-
enforce some kind of maximum queue depth for
|
|
809
|
+
The number of commands that have been sent to the Redis server but not yet
|
|
810
|
+
replied to. You can use this to enforce some kind of maximum queue depth for
|
|
811
|
+
commands while connected.
|
|
704
812
|
|
|
705
813
|
## client.offline_queue_length
|
|
706
814
|
|
|
707
|
-
The number of commands that have been queued up for a future connection. You can
|
|
708
|
-
some kind of maximum queue depth for pre-connection
|
|
815
|
+
The number of commands that have been queued up for a future connection. You can
|
|
816
|
+
use this to enforce some kind of maximum queue depth for pre-connection
|
|
817
|
+
commands.
|
|
709
818
|
|
|
710
819
|
### Commands with Optional and Keyword arguments
|
|
711
820
|
|
|
712
|
-
This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset
|
|
821
|
+
This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset
|
|
822
|
+
count]` in the [redis.io/commands](http://redis.io/commands) documentation.
|
|
713
823
|
|
|
714
824
|
Example:
|
|
825
|
+
|
|
715
826
|
```js
|
|
716
827
|
var args = [ 'myzset', 1, 'one', 2, 'two', 3, 'three', 99, 'ninety-nine' ];
|
|
717
828
|
client.zadd(args, function (err, response) {
|
|
@@ -784,10 +895,13 @@ clients: 1, NodeJS: 6.2.0, Redis: 3.2.0, parser: javascript, connected by: tcp
|
|
|
784
895
|
|
|
785
896
|
To get debug output run your `node_redis` application with `NODE_DEBUG=redis`.
|
|
786
897
|
|
|
787
|
-
This is also going to result in good stack traces opposed to useless ones
|
|
788
|
-
|
|
898
|
+
This is also going to result in good stack traces opposed to useless ones
|
|
899
|
+
otherwise for any async operation.
|
|
900
|
+
If you only want to have good stack traces but not the debug output run your
|
|
901
|
+
application in development mode instead (`NODE_ENV=development`).
|
|
789
902
|
|
|
790
|
-
Good stack traces are only activated in development and debug mode as this
|
|
903
|
+
Good stack traces are only activated in development and debug mode as this
|
|
904
|
+
results in a significant performance penalty.
|
|
791
905
|
|
|
792
906
|
___Comparison___:
|
|
793
907
|
Useless stack trace:
|
|
@@ -823,7 +937,8 @@ The original author of node_redis is [Matthew Ranney](https://github.com/mranney
|
|
|
823
937
|
|
|
824
938
|
The current lead maintainer is [Ruben Bridgewater](https://github.com/BridgeAR)
|
|
825
939
|
|
|
826
|
-
Many [others](https://github.com/NodeRedis/node_redis/graphs/contributors)
|
|
940
|
+
Many [others](https://github.com/NodeRedis/node_redis/graphs/contributors)
|
|
941
|
+
contributed to `node_redis` too. Thanks to all of them!
|
|
827
942
|
|
|
828
943
|
## License
|
|
829
944
|
|
|
@@ -831,10 +946,20 @@ Many [others](https://github.com/NodeRedis/node_redis/graphs/contributors) contr
|
|
|
831
946
|
|
|
832
947
|
### Consolidation: It's time for celebration
|
|
833
948
|
|
|
834
|
-
Right now there are two great redis clients around and both have some advantages
|
|
949
|
+
Right now there are two great redis clients around and both have some advantages
|
|
950
|
+
above each other. We speak about ioredis and node_redis. So after talking to
|
|
951
|
+
each other about how we could improve in working together we (that is @luin and
|
|
952
|
+
@BridgeAR) decided to work towards a single library on the long run. But step by
|
|
953
|
+
step.
|
|
835
954
|
|
|
836
|
-
First of all, we want to split small parts of our libraries into others so that
|
|
955
|
+
First of all, we want to split small parts of our libraries into others so that
|
|
956
|
+
we're both able to use the same code. Those libraries are going to be maintained
|
|
957
|
+
under the NodeRedis organization. This is going to reduce the maintenance
|
|
958
|
+
overhead, allows others to use the very same code, if they need it and it's way
|
|
959
|
+
easyer for others to contribute to both libraries.
|
|
837
960
|
|
|
838
|
-
We're very happy about this step towards working together as we both want to
|
|
961
|
+
We're very happy about this step towards working together as we both want to
|
|
962
|
+
give you the best redis experience possible.
|
|
839
963
|
|
|
840
|
-
If you want to join our cause by help maintaining something, please don't
|
|
964
|
+
If you want to join our cause by help maintaining something, please don't
|
|
965
|
+
hesitate to contact either one of us.
|
package/changelog.md
CHANGED
|
@@ -1,30 +1,66 @@
|
|
|
1
|
-
Changelog
|
|
2
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v.2.8.0 - 31 Jul, 2017
|
|
4
|
+
|
|
5
|
+
Features
|
|
6
|
+
|
|
7
|
+
- Accept UPPER_CASE commands in send_command
|
|
8
|
+
- Add arbitrary commands to the prototype by using `Redis.addCommand(name)`
|
|
9
|
+
|
|
10
|
+
Bugfixes
|
|
11
|
+
|
|
12
|
+
- Fixed not always copying subscribe unsubscribe arguments
|
|
13
|
+
- Fixed emitting internal errors while reconnecting with auth
|
|
14
|
+
- Fixed crashing with invalid url option
|
|
15
|
+
|
|
16
|
+
## v.2.7.1 - 14 Mar, 2017
|
|
17
|
+
|
|
18
|
+
Bugfixes
|
|
19
|
+
|
|
20
|
+
- Fixed monitor mode not working in combination with IPv6 (2.6.0 regression)
|
|
21
|
+
|
|
22
|
+
## v.2.7.0 - 11 Mar, 2017
|
|
23
|
+
|
|
24
|
+
Features
|
|
25
|
+
|
|
26
|
+
- All returned errors are from now a subclass of `RedisError`.
|
|
27
|
+
|
|
28
|
+
Bugfixes
|
|
29
|
+
|
|
30
|
+
- Fixed rename_commands not accepting `null` as value
|
|
31
|
+
- Fixed `AbortError`s and `AggregateError`s not showing the error message in the stack trace
|
|
32
|
+
|
|
33
|
+
## v.2.6.5 - 15 Jan, 2017
|
|
34
|
+
|
|
35
|
+
Bugfixes
|
|
36
|
+
|
|
37
|
+
- Fixed parser not being reset in case the redis connection closed ASAP for overcoming of output buffer limits
|
|
38
|
+
- Fixed parser reset if (p)message_buffer listener is attached
|
|
3
39
|
|
|
4
40
|
## v.2.6.4 - 12 Jan, 2017
|
|
5
41
|
|
|
6
42
|
Bugfixes
|
|
7
43
|
|
|
8
|
-
-
|
|
44
|
+
- Fixed monitor mode not working in combination with IPv6, sockets or lua scripts (2.6.0 regression)
|
|
9
45
|
|
|
10
46
|
## v.2.6.3 - 31 Oct, 2016
|
|
11
47
|
|
|
12
48
|
Bugfixes
|
|
13
49
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
50
|
+
- Do not change the tls setting to camel_case
|
|
51
|
+
- Fix domain handling in combination with the offline queue (2.5.3 regression)
|
|
16
52
|
|
|
17
53
|
## v.2.6.2 - 16 Jun, 2016
|
|
18
54
|
|
|
19
55
|
Bugfixes
|
|
20
56
|
|
|
21
|
-
-
|
|
57
|
+
- Fixed individual callbacks of a transaction not being called (2.6.0 regression)
|
|
22
58
|
|
|
23
59
|
## v.2.6.1 - 02 Jun, 2016
|
|
24
60
|
|
|
25
61
|
Bugfixes
|
|
26
62
|
|
|
27
|
-
-
|
|
63
|
+
- Fixed invalid function name being exported
|
|
28
64
|
|
|
29
65
|
## v.2.6.0 - 01 Jun, 2016
|
|
30
66
|
|
|
@@ -106,7 +142,7 @@ Features
|
|
|
106
142
|
- Monitor and pub sub mode now work together with the offline queue
|
|
107
143
|
- All commands that were send after a connection loss are now going to be send after reconnecting
|
|
108
144
|
- Activating monitor mode does now work together with arbitrary commands including pub sub mode
|
|
109
|
-
- Pub sub mode is
|
|
145
|
+
- Pub sub mode is completely rewritten and all known issues fixed
|
|
110
146
|
- Added `string_numbers` option to get back strings instead of numbers
|
|
111
147
|
- Quit command is from now on always going to end the connection properly
|
|
112
148
|
|
|
@@ -149,7 +185,7 @@ Same changelog as the pre-release
|
|
|
149
185
|
|
|
150
186
|
## v.2.5.0-1 - 07 Mar, 2016
|
|
151
187
|
|
|
152
|
-
This is a big release with some
|
|
188
|
+
This is a big release with some substantial underlining changes. Therefor this is released as a pre-release and I encourage anyone who's able to, to test this out.
|
|
153
189
|
|
|
154
190
|
It took way to long to release this one and the next release cycles will be shorter again.
|
|
155
191
|
|
|
@@ -169,7 +205,7 @@ Features
|
|
|
169
205
|
- Added a `warning` emitter that receives node_redis warnings like auth not required and deprecation messages
|
|
170
206
|
- Added a `retry_strategy` option that replaces all reconnect options
|
|
171
207
|
- The reconnecting event from now on also receives:
|
|
172
|
-
- The error message why the reconnect
|
|
208
|
+
- The error message why the reconnect happened (params.error)
|
|
173
209
|
- The amount of times the client was connected (params.times_connected)
|
|
174
210
|
- The total reconnecting time since the last time connected (params.total_retry_time)
|
|
175
211
|
- Always respect the command execution order no matter if the reply could be returned sync or not (former exceptions: [#937](https://github.com/NodeRedis/node_redis/issues/937#issuecomment-167525939))
|
|
@@ -184,9 +220,9 @@ Bugfixes
|
|
|
184
220
|
- Fixed do not run toString on an array argument and throw a "invalid data" error instead
|
|
185
221
|
- This is not considered as breaking change, as this is likely a error in your code and if you want to have such a behavior you should handle this beforehand
|
|
186
222
|
- The same applies to Map / Set and individual Object types
|
|
187
|
-
- Fixed redis url not accepting the protocol being omitted or protocols other than the redis protocol for
|
|
223
|
+
- Fixed redis url not accepting the protocol being omitted or protocols other than the redis protocol for convenience
|
|
188
224
|
- Fixed parsing the db keyspace even if the first database does not begin with a zero
|
|
189
|
-
- Fixed handling of errors
|
|
225
|
+
- Fixed handling of errors occurring while receiving pub sub messages
|
|
190
226
|
- Fixed huge string pipelines crashing NodeJS (Pipeline size above 256mb)
|
|
191
227
|
- Fixed rename_commands and prefix option not working together
|
|
192
228
|
- Fixed ready being emitted to early in case a slave is still syncing / master down
|
|
@@ -199,7 +235,7 @@ Deprecations
|
|
|
199
235
|
- Using SET or SETEX with a undefined or null value will from now on also result in converting the value to "null" / "undefined" to have a consistent behavior. This is not considered as breaking change, as it returned an error earlier.
|
|
200
236
|
- Using .end(flush) without the flush parameter is deprecated and the flush parameter should explicitly be used
|
|
201
237
|
- From v.3.0.0 on using .end without flush will result in an error
|
|
202
|
-
- Using .end without flush means that any command that did not yet return is going to silently fail. Therefor this is considered
|
|
238
|
+
- Using .end without flush means that any command that did not yet return is going to silently fail. Therefor this is considered harmful and you should explicitly silence such errors if you are sure you want this
|
|
203
239
|
- Depending on the return value of a command to detect the backpressure is deprecated
|
|
204
240
|
- From version 3.0.0 on node_redis might not return true / false as a return value anymore. Please rely on client.should_buffer instead
|
|
205
241
|
- The `socket_nodelay` option is deprecated and will be removed in v.3.0.0
|
package/index.js
CHANGED
|
@@ -120,7 +120,7 @@ function RedisClient (options, stream) {
|
|
|
120
120
|
if ('max_attempts' in options) {
|
|
121
121
|
self.warn(
|
|
122
122
|
'max_attempts is deprecated and will be removed in v.3.0.0.\n' +
|
|
123
|
-
'To reduce the
|
|
123
|
+
'To reduce the number of options and to improve the reconnection handling please use the new `retry_strategy` option instead.\n' +
|
|
124
124
|
'This replaces the max_attempts and retry_max_delay option.'
|
|
125
125
|
);
|
|
126
126
|
}
|
|
@@ -156,8 +156,6 @@ function RedisClient (options, stream) {
|
|
|
156
156
|
this.buffers = options.return_buffers || options.detect_buffers;
|
|
157
157
|
this.options = options;
|
|
158
158
|
this.reply = 'ON'; // Returning replies is the default
|
|
159
|
-
// Init parser
|
|
160
|
-
this.reply_parser = create_parser(this);
|
|
161
159
|
this.create_stream();
|
|
162
160
|
// The listeners will not be attached right away, so let's print the deprecation message while the listener is attached
|
|
163
161
|
this.on('newListener', function (event) {
|
|
@@ -171,10 +169,16 @@ function RedisClient (options, stream) {
|
|
|
171
169
|
'The drain event listener is deprecated and will be removed in v.3.0.0.\n' +
|
|
172
170
|
'If you want to keep on listening to this event please listen to the stream drain event directly.'
|
|
173
171
|
);
|
|
174
|
-
} else if (event === 'message_buffer' || event === 'pmessage_buffer' || event === 'messageBuffer' || event === 'pmessageBuffer' && !this.buffers) {
|
|
172
|
+
} else if ((event === 'message_buffer' || event === 'pmessage_buffer' || event === 'messageBuffer' || event === 'pmessageBuffer') && !this.buffers && !this.message_buffers) {
|
|
173
|
+
if (this.reply_parser.name !== 'javascript') {
|
|
174
|
+
return this.warn(
|
|
175
|
+
'You attached the "' + event + '" listener without the returnBuffers option set to true.\n' +
|
|
176
|
+
'Please use the JavaScript parser or set the returnBuffers option to true to return buffers.'
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
this.reply_parser.optionReturnBuffers = true;
|
|
175
180
|
this.message_buffers = true;
|
|
176
181
|
this.handle_reply = handle_detect_buffers_reply;
|
|
177
|
-
this.reply_parser = create_parser(this);
|
|
178
182
|
}
|
|
179
183
|
});
|
|
180
184
|
}
|
|
@@ -224,6 +228,9 @@ function create_parser (self) {
|
|
|
224
228
|
RedisClient.prototype.create_stream = function () {
|
|
225
229
|
var self = this;
|
|
226
230
|
|
|
231
|
+
// Init parser
|
|
232
|
+
this.reply_parser = create_parser(this);
|
|
233
|
+
|
|
227
234
|
if (this.options.stream) {
|
|
228
235
|
// Only add the listeners once in case of a reconnect try (that won't work)
|
|
229
236
|
if (this.stream) {
|
|
@@ -297,7 +304,12 @@ RedisClient.prototype.create_stream = function () {
|
|
|
297
304
|
// Fire the command before redis is connected to be sure it's the first fired command
|
|
298
305
|
if (this.auth_pass !== undefined) {
|
|
299
306
|
this.ready = true;
|
|
300
|
-
|
|
307
|
+
// Fail silently as we might not be able to connect
|
|
308
|
+
this.auth(this.auth_pass, function (err) {
|
|
309
|
+
if (err && err.code !== 'UNCERTAIN_STATE') {
|
|
310
|
+
self.emit('error', err);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
301
313
|
this.ready = false;
|
|
302
314
|
}
|
|
303
315
|
};
|
|
@@ -924,7 +936,7 @@ RedisClient.prototype.internal_send_command = function (command_obj) {
|
|
|
924
936
|
args_copy[i] = this.options.prefix + args_copy[i];
|
|
925
937
|
}
|
|
926
938
|
}
|
|
927
|
-
if (
|
|
939
|
+
if (this.options.rename_commands && this.options.rename_commands[command]) {
|
|
928
940
|
command = this.options.rename_commands[command];
|
|
929
941
|
}
|
|
930
942
|
// Always use 'Multi bulk commands', but if passed any Buffer args, then do multiple writes, one for each arg.
|
|
@@ -1080,10 +1092,14 @@ exports.RedisClient = RedisClient;
|
|
|
1080
1092
|
exports.print = utils.print;
|
|
1081
1093
|
exports.Multi = require('./lib/multi');
|
|
1082
1094
|
exports.AbortError = errorClasses.AbortError;
|
|
1095
|
+
exports.RedisError = Parser.RedisError;
|
|
1096
|
+
exports.ParserError = Parser.ParserError;
|
|
1083
1097
|
exports.ReplyError = Parser.ReplyError;
|
|
1084
1098
|
exports.AggregateError = errorClasses.AggregateError;
|
|
1085
1099
|
|
|
1086
1100
|
// Add all redis commands / node_redis api to the client
|
|
1087
1101
|
require('./lib/individualCommands');
|
|
1088
1102
|
require('./lib/extendedApi');
|
|
1089
|
-
|
|
1103
|
+
|
|
1104
|
+
//enables adding new commands (for modules and new commands)
|
|
1105
|
+
exports.addCommand = exports.add_command = require('./lib/commands');
|
package/lib/commands.js
CHANGED
|
@@ -17,11 +17,7 @@ var changeFunctionName = (function () {
|
|
|
17
17
|
}
|
|
18
18
|
}());
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
// that provided a functionality to add new commands to the client
|
|
22
|
-
|
|
23
|
-
commands.list.forEach(function (command) {
|
|
24
|
-
|
|
20
|
+
var addCommand = function (command) {
|
|
25
21
|
// Some rare Redis commands use special characters in their command name
|
|
26
22
|
// Convert those to a underscore to prevent using invalid function names
|
|
27
23
|
var commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1');
|
|
@@ -61,6 +57,10 @@ commands.list.forEach(function (command) {
|
|
|
61
57
|
}
|
|
62
58
|
return this.internal_send_command(new Command(command, arr, callback));
|
|
63
59
|
};
|
|
60
|
+
// Alias special function names (e.g. NR.RUN becomes NR_RUN and nr_run)
|
|
61
|
+
if (commandName !== command) {
|
|
62
|
+
RedisClient.prototype[commandName.toUpperCase()] = RedisClient.prototype[commandName] = RedisClient.prototype[command];
|
|
63
|
+
}
|
|
64
64
|
if (changeFunctionName) {
|
|
65
65
|
Object.defineProperty(RedisClient.prototype[command], 'name', {
|
|
66
66
|
value: commandName
|
|
@@ -104,10 +104,18 @@ commands.list.forEach(function (command) {
|
|
|
104
104
|
this.queue.push(new Command(command, arr, callback));
|
|
105
105
|
return this;
|
|
106
106
|
};
|
|
107
|
+
// Alias special function names (e.g. NR.RUN becomes NR_RUN and nr_run)
|
|
108
|
+
if (commandName !== command) {
|
|
109
|
+
Multi.prototype[commandName.toUpperCase()] = Multi.prototype[commandName] = Multi.prototype[command];
|
|
110
|
+
}
|
|
107
111
|
if (changeFunctionName) {
|
|
108
112
|
Object.defineProperty(Multi.prototype[command], 'name', {
|
|
109
113
|
value: commandName
|
|
110
114
|
});
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
|
-
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
commands.list.forEach(addCommand);
|
|
120
|
+
|
|
121
|
+
module.exports = addCommand;
|
package/lib/createClient.js
CHANGED
|
@@ -23,7 +23,8 @@ module.exports = function createClient (port_arg, host_arg, options) {
|
|
|
23
23
|
} else if (typeof port_arg === 'string' || port_arg && port_arg.url) {
|
|
24
24
|
|
|
25
25
|
options = utils.clone(port_arg.url ? port_arg : host_arg || options);
|
|
26
|
-
var
|
|
26
|
+
var url = port_arg.url || port_arg;
|
|
27
|
+
var parsed = URL.parse(url, true, true);
|
|
27
28
|
|
|
28
29
|
// [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
|
|
29
30
|
if (parsed.slashes) { // We require slashes
|
|
@@ -59,7 +60,7 @@ module.exports = function createClient (port_arg, host_arg, options) {
|
|
|
59
60
|
} else if (parsed.hostname) {
|
|
60
61
|
throw new RangeError('The redis url must begin with slashes "//" or contain slashes after the redis protocol');
|
|
61
62
|
} else {
|
|
62
|
-
options.path =
|
|
63
|
+
options.path = url;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
} else if (typeof port_arg === 'object' || port_arg === undefined) {
|
package/lib/customErrors.js
CHANGED
|
@@ -1,42 +1,55 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var util = require('util');
|
|
4
|
+
var assert = require('assert');
|
|
5
|
+
var RedisError = require('redis-parser').RedisError;
|
|
6
|
+
var ADD_STACKTRACE = false;
|
|
4
7
|
|
|
5
|
-
function AbortError (obj) {
|
|
6
|
-
|
|
8
|
+
function AbortError (obj, stack) {
|
|
9
|
+
assert(obj, 'The options argument is required');
|
|
10
|
+
assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object');
|
|
11
|
+
|
|
12
|
+
RedisError.call(this, obj.message, ADD_STACKTRACE);
|
|
7
13
|
Object.defineProperty(this, 'message', {
|
|
8
14
|
value: obj.message || '',
|
|
9
15
|
configurable: true,
|
|
10
16
|
writable: true
|
|
11
17
|
});
|
|
18
|
+
if (stack || stack === undefined) {
|
|
19
|
+
Error.captureStackTrace(this, AbortError);
|
|
20
|
+
}
|
|
12
21
|
for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) {
|
|
13
22
|
this[key] = obj[key];
|
|
14
23
|
}
|
|
15
24
|
}
|
|
16
25
|
|
|
17
26
|
function AggregateError (obj) {
|
|
18
|
-
|
|
27
|
+
assert(obj, 'The options argument is required');
|
|
28
|
+
assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object');
|
|
29
|
+
|
|
30
|
+
AbortError.call(this, obj, ADD_STACKTRACE);
|
|
19
31
|
Object.defineProperty(this, 'message', {
|
|
20
32
|
value: obj.message || '',
|
|
21
33
|
configurable: true,
|
|
22
34
|
writable: true
|
|
23
35
|
});
|
|
36
|
+
Error.captureStackTrace(this, AggregateError);
|
|
24
37
|
for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) {
|
|
25
38
|
this[key] = obj[key];
|
|
26
39
|
}
|
|
27
40
|
}
|
|
28
41
|
|
|
29
|
-
util.inherits(AbortError,
|
|
42
|
+
util.inherits(AbortError, RedisError);
|
|
30
43
|
util.inherits(AggregateError, AbortError);
|
|
31
44
|
|
|
32
45
|
Object.defineProperty(AbortError.prototype, 'name', {
|
|
33
46
|
value: 'AbortError',
|
|
34
|
-
|
|
47
|
+
configurable: true,
|
|
35
48
|
writable: true
|
|
36
49
|
});
|
|
37
50
|
Object.defineProperty(AggregateError.prototype, 'name', {
|
|
38
51
|
value: 'AggregateError',
|
|
39
|
-
|
|
52
|
+
configurable: true,
|
|
40
53
|
writable: true
|
|
41
54
|
});
|
|
42
55
|
|
package/lib/extendedApi.js
CHANGED
|
@@ -16,6 +16,7 @@ RedisClient.prototype.send_command = RedisClient.prototype.sendCommand = functio
|
|
|
16
16
|
if (typeof command !== 'string') {
|
|
17
17
|
throw new TypeError('Wrong input type "' + (command !== null && command !== undefined ? command.constructor.name : command) + '" for command name');
|
|
18
18
|
}
|
|
19
|
+
command = command.toLowerCase();
|
|
19
20
|
if (!Array.isArray(args)) {
|
|
20
21
|
if (args === undefined || args === null) {
|
|
21
22
|
args = [];
|
|
@@ -32,9 +33,9 @@ RedisClient.prototype.send_command = RedisClient.prototype.sendCommand = functio
|
|
|
32
33
|
|
|
33
34
|
// Using the raw multi command is only possible with this function
|
|
34
35
|
// If the command is not yet added to the client, the internal function should be called right away
|
|
35
|
-
// Otherwise we need to redirect the calls to make sure the
|
|
36
|
+
// Otherwise we need to redirect the calls to make sure the internal functions don't get skipped
|
|
36
37
|
// The internal functions could actually be used for any non hooked function
|
|
37
|
-
// but this might change from time to time and at the moment there's no good way to
|
|
38
|
+
// but this might change from time to time and at the moment there's no good way to distinguish them
|
|
38
39
|
// from each other, so let's just do it do it this way for the time being
|
|
39
40
|
if (command === 'multi' || typeof this[command] !== 'function') {
|
|
40
41
|
return this.internal_send_command(new Command(command, args, callback));
|
|
@@ -398,7 +398,7 @@ RedisClient.prototype.subscribe = RedisClient.prototype.SUBSCRIBE = function sub
|
|
|
398
398
|
callback,
|
|
399
399
|
i = 0;
|
|
400
400
|
if (Array.isArray(arguments[0])) {
|
|
401
|
-
arr = arguments[0];
|
|
401
|
+
arr = arguments[0].slice(0);
|
|
402
402
|
callback = arguments[1];
|
|
403
403
|
} else {
|
|
404
404
|
len = arguments.length;
|
|
@@ -425,7 +425,7 @@ Multi.prototype.subscribe = Multi.prototype.SUBSCRIBE = function subscribe () {
|
|
|
425
425
|
callback,
|
|
426
426
|
i = 0;
|
|
427
427
|
if (Array.isArray(arguments[0])) {
|
|
428
|
-
arr = arguments[0];
|
|
428
|
+
arr = arguments[0].slice(0);
|
|
429
429
|
callback = arguments[1];
|
|
430
430
|
} else {
|
|
431
431
|
len = arguments.length;
|
|
@@ -453,7 +453,7 @@ RedisClient.prototype.unsubscribe = RedisClient.prototype.UNSUBSCRIBE = function
|
|
|
453
453
|
callback,
|
|
454
454
|
i = 0;
|
|
455
455
|
if (Array.isArray(arguments[0])) {
|
|
456
|
-
arr = arguments[0];
|
|
456
|
+
arr = arguments[0].slice(0);
|
|
457
457
|
callback = arguments[1];
|
|
458
458
|
} else {
|
|
459
459
|
len = arguments.length;
|
|
@@ -481,7 +481,7 @@ Multi.prototype.unsubscribe = Multi.prototype.UNSUBSCRIBE = function unsubscribe
|
|
|
481
481
|
callback,
|
|
482
482
|
i = 0;
|
|
483
483
|
if (Array.isArray(arguments[0])) {
|
|
484
|
-
arr = arguments[0];
|
|
484
|
+
arr = arguments[0].slice(0);
|
|
485
485
|
callback = arguments[1];
|
|
486
486
|
} else {
|
|
487
487
|
len = arguments.length;
|
|
@@ -510,7 +510,7 @@ RedisClient.prototype.psubscribe = RedisClient.prototype.PSUBSCRIBE = function p
|
|
|
510
510
|
callback,
|
|
511
511
|
i = 0;
|
|
512
512
|
if (Array.isArray(arguments[0])) {
|
|
513
|
-
arr = arguments[0];
|
|
513
|
+
arr = arguments[0].slice(0);
|
|
514
514
|
callback = arguments[1];
|
|
515
515
|
} else {
|
|
516
516
|
len = arguments.length;
|
|
@@ -537,7 +537,7 @@ Multi.prototype.psubscribe = Multi.prototype.PSUBSCRIBE = function psubscribe ()
|
|
|
537
537
|
callback,
|
|
538
538
|
i = 0;
|
|
539
539
|
if (Array.isArray(arguments[0])) {
|
|
540
|
-
arr = arguments[0];
|
|
540
|
+
arr = arguments[0].slice(0);
|
|
541
541
|
callback = arguments[1];
|
|
542
542
|
} else {
|
|
543
543
|
len = arguments.length;
|
|
@@ -565,7 +565,7 @@ RedisClient.prototype.punsubscribe = RedisClient.prototype.PUNSUBSCRIBE = functi
|
|
|
565
565
|
callback,
|
|
566
566
|
i = 0;
|
|
567
567
|
if (Array.isArray(arguments[0])) {
|
|
568
|
-
arr = arguments[0];
|
|
568
|
+
arr = arguments[0].slice(0);
|
|
569
569
|
callback = arguments[1];
|
|
570
570
|
} else {
|
|
571
571
|
len = arguments.length;
|
|
@@ -593,7 +593,7 @@ Multi.prototype.punsubscribe = Multi.prototype.PUNSUBSCRIBE = function punsubscr
|
|
|
593
593
|
callback,
|
|
594
594
|
i = 0;
|
|
595
595
|
if (Array.isArray(arguments[0])) {
|
|
596
|
-
arr = arguments[0];
|
|
596
|
+
arr = arguments[0].slice(0);
|
|
597
597
|
callback = arguments[1];
|
|
598
598
|
} else {
|
|
599
599
|
len = arguments.length;
|
package/lib/utils.js
CHANGED
|
@@ -127,7 +127,7 @@ module.exports = {
|
|
|
127
127
|
reply_to_object: replyToObject,
|
|
128
128
|
print: print,
|
|
129
129
|
err_code: /^([A-Z]+)\s+(.+)$/,
|
|
130
|
-
monitor_regex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]
|
|
130
|
+
monitor_regex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]+ .+\]( ".+?")+$/,
|
|
131
131
|
clone: convenienceClone,
|
|
132
132
|
callback_or_emit: callbackOrEmit,
|
|
133
133
|
reply_in_order: replyInOrder
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redis",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Redis client library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"database",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"double-ended-queue": "^2.1.0-0",
|
|
29
29
|
"redis-commands": "^1.2.0",
|
|
30
|
-
"redis-parser": "^2.
|
|
30
|
+
"redis-parser": "^2.6.0"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=0.10.0"
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"bluebird": "^3.0.2",
|
|
37
37
|
"coveralls": "^2.11.2",
|
|
38
|
+
"eslint": "^4.2.0",
|
|
38
39
|
"intercept-stdout": "~0.1.2",
|
|
39
|
-
"eslint": "^3.5.0",
|
|
40
40
|
"metrics": "^0.1.9",
|
|
41
|
-
"mocha": "^
|
|
42
|
-
"nyc": "^
|
|
41
|
+
"mocha": "^3.1.2",
|
|
42
|
+
"nyc": "^10.0.0",
|
|
43
43
|
"tcp-port-used": "^0.1.2",
|
|
44
44
|
"uuid": "^2.0.1",
|
|
45
45
|
"win-spawn": "^2.0.0"
|