1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-10 11:43:01 +03:00
This commit is contained in:
Salakar
2020-02-09 02:28:12 +00:00
parent bb05064b14
commit 7ce0858456
3 changed files with 436 additions and 504 deletions

View File

@@ -3,7 +3,7 @@
"trailingComma": "all", "trailingComma": "all",
"useTabs": false, "useTabs": false,
"semi": true, "semi": true,
"singleQuote": true, "singleQuote": false,
"bracketSpacing": true, "bracketSpacing": true,
"jsxBracketSameLine": false, "jsxBracketSameLine": false,
"tabWidth": 2, "tabWidth": 2,

File diff suppressed because it is too large Load Diff

277
README.md
View File

@@ -19,115 +19,43 @@
--- ---
This is a complete and feature rich Redis client for Node.js. **It supports all ## Installation
Redis commands** and focuses on high performance.
Install with:
```bash ```bash
npm install redis npm install redis
``` ```
## Usage Example ## Usage
#### Example
```js ```js
const redis = require('redis'); const redis = require("redis");
const client = redis.createClient(); const client = redis.createClient();
// if you'd like to select database 3, instead of 0 (default), call client.on("error", function(err) {
// client.select(3, function() { /* ... */ }); console.log("Error " + err);
client.on('error', function(err) {
console.log('Error ' + err);
}); });
client.set('string key', 'string val', redis.print); client.set("string key", "string val", redis.print);
client.hset('hash key', 'hashtest 1', 'some value', redis.print); client.get("string key", redis.print);
client.hset(['hash key', 'hashtest 2', 'some other value'], redis.print);
client.hkeys('hash key', function(err, replies) {
console.log(replies.length + ' replies:');
replies.forEach(function(reply, i) {
console.log(' ' + i + ': ' + reply);
});
client.quit();
});
``` ```
This will display:
mjr:~/work/node_redis (master)$ node example.js
Reply: OK
Reply: 0
Reply: 0
2 replies:
0: hashtest 1
1: hashtest 2
mjr:~/work/node_redis (master)$
Note that the API is entirely asynchronous. To get data back from the server, Note that the API is entirely asynchronous. To get data back from the server,
you'll need to use a callback. From v.2.6 on the API supports camelCase and you'll need to use a callback.
snake_case and all options / variables / events etc. can be used either way. It
is recommended to use camelCase as this is the default for the Node.js
landscape.
### Promises ### Promises
#### Native Promises Node Redis currently doesn't natively support promises (this is coming in v4), however you can wrap the methods you
want to use with promises using the built-in Node.js `util.promisify` method on Node.js >= v8;
If you are using node v8 or higher, you can promisify node_redis with [util.promisify](https://nodejs.org/api/util.html#util_util_promisify_original) as in:
```js ```js
const { promisify } = require('util'); const { promisify } = require("util");
const getAsync = promisify(client.get).bind(client); const getAsync = promisify(client.get).bind(client);
```
now _getAsync_ is a promisified version of _client.get_: getAsync
.then(console.log)
```js .catch(console.error);
// We expect a value 'foo': 'bar' to be present
// So instead of writing client.get('foo', cb); you have to write:
return getAsync('foo').then(function(res) {
console.log(res); // => 'bar'
});
```
or using [async await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function):
```js
async function myFunc() {
const res = await getAsync('foo');
console.log(res);
}
```
#### Bluebird Promises
You can also use node_redis with promises by promisifying node_redis with
[bluebird](https://github.com/petkaantonov/bluebird) as in:
```js
const redis = require('redis');
bluebird.promisifyAll(redis);
```
It'll add a _Async_ to all node_redis functions (e.g. return client.getAsync().then())
```js
// We expect a value 'foo': 'bar' to be present
// So instead of writing client.get('foo', cb); you have to write:
return client.getAsync('foo').then(function(res) {
console.log(res); // => 'bar'
});
// Using multi with promises looks like:
return client
.multi()
.get('foo')
.execAsync()
.then(function(res) {
console.log(res); // => 'bar'
});
``` ```
### Sending Commands ### Sending Commands
@@ -138,16 +66,15 @@ a variable number of individual arguments followed by an optional callback.
Examples: Examples:
```js ```js
client.hmset(['key', 'test keys 1', 'test val 1', 'test keys 2', 'test val 2'], function( client.hmset(["key", "test keys 1", "test val 1", "test keys 2", "test val 2"], function(err, res) {
err, // ...
res, });
) {});
// Works the same as // Works the same as
client.hmset('key', ['test keys 1', 'test val 1', 'test keys 2', 'test val 2'], function(err, res) { client.hmset("key", ["test keys 1", "test val 1", "test keys 2", "test val 2"], function(err, res) {
// ... // ...
}); });
// Or // Or
client.hmset('key', 'test keys 1', 'test val 1', 'test keys 2', 'test val 2', function(err, res) { client.hmset("key", "test keys 1", "test val 1", "test keys 2", "test val 2", function(err, res) {
// ... // ...
}); });
``` ```
@@ -157,15 +84,15 @@ Care should be taken with user input if arrays are possible (via body-parser, qu
Note that in either form the `callback` is optional: Note that in either form the `callback` is optional:
```js ```js
client.set('some key', 'some val'); client.set("some key", "some val");
client.set(['some other key', 'some val']); client.set(["some other key", "some val"]);
``` ```
If the key is missing, reply will be null. Only if the [Redis Command If the key is missing, reply will be null. Only if the [Redis Command
Reference](http://redis.io/commands) states something else it will not be null. Reference](http://redis.io/commands) states something else it will not be null.
```js ```js
client.get('missingkey', function(err, reply) { client.get("missingkey", function(err, reply) {
// reply is null when the key is missing // reply is null when the key is missing
console.log(reply); console.log(reply);
}); });
@@ -189,7 +116,7 @@ Example setting key to auto expire using [SET command](https://redis.io/commands
```js ```js
// this key will expire after 10 seconds // this key will expire after 10 seconds
client.set('key', 'value!', 'EX', 10); client.set("key", "value!", "EX", 10);
``` ```
# API # API
@@ -275,18 +202,18 @@ using unix sockets if possible to increase throughput.
| 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. | | 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. |
```js ```js
var redis = require('redis'); var redis = require("redis");
var client = redis.createClient({ detect_buffers: true }); var client = redis.createClient({ detect_buffers: true });
client.set('foo_rand000000000000', 'OK'); client.set("foo_rand000000000000", "OK");
// This will return a JavaScript String // This will return a JavaScript String
client.get('foo_rand000000000000', function(err, reply) { client.get("foo_rand000000000000", function(err, reply) {
console.log(reply.toString()); // Will print `OK` console.log(reply.toString()); // Will print `OK`
}); });
// This will return a Buffer since original key is specified as a Buffer // This will return a Buffer since original key is specified as a Buffer
client.get(new Buffer('foo_rand000000000000'), function(err, reply) { client.get(new Buffer("foo_rand000000000000"), function(err, reply) {
console.log(reply.toString()); // Will print `<Buffer 4f 4b>` console.log(reply.toString()); // Will print `<Buffer 4f 4b>`
}); });
client.quit(); client.quit();
@@ -297,15 +224,15 @@ client.quit();
```js ```js
var client = redis.createClient({ var client = redis.createClient({
retry_strategy: function(options) { retry_strategy: function(options) {
if (options.error && options.error.code === 'ECONNREFUSED') { if (options.error && options.error.code === "ECONNREFUSED") {
// End reconnecting on a specific error and flush all commands with // End reconnecting on a specific error and flush all commands with
// a individual error // a individual error
return new Error('The server refused the connection'); return new Error("The server refused the connection");
} }
if (options.total_retry_time > 1000 * 60 * 60) { if (options.total_retry_time > 1000 * 60 * 60) {
// End reconnecting after a specific timeout and flush all commands // End reconnecting after a specific timeout and flush all commands
// with a individual error // with a individual error
return new Error('Retry time exhausted'); return new Error("Retry time exhausted");
} }
if (options.attempt > 10) { if (options.attempt > 10) {
// End reconnecting with built in error // End reconnecting with built in error
@@ -363,23 +290,23 @@ This example closes the connection to the Redis server before the replies have
been read. You probably don't want to do this: been read. You probably don't want to do this:
```js ```js
var redis = require('redis'), var redis = require("redis"),
client = redis.createClient(); client = redis.createClient();
client.set('foo_rand000000000000', 'some fantastic value', function(err, reply) { client.set("foo_rand000000000000", "some fantastic value", function(err, reply) {
// This will either result in an error (flush parameter is set to true) // This will either result in an error (flush parameter is set to true)
// or will silently fail and this callback will not be called at all (flush set to false) // or will silently fail and this callback will not be called at all (flush set to false)
console.log(err); console.log(err);
}); });
client.end(true); // No further commands will be processed client.end(true); // No further commands will be processed
client.get('foo_rand000000000000', function(err, reply) { client.get("foo_rand000000000000", function(err, reply) {
console.log(err); // => 'The connection has already been closed.' console.log(err); // => 'The connection has already been closed.'
}); });
``` ```
`client.end()` without the flush parameter set to true should NOT be used in production! `client.end()` without the flush parameter set to true should NOT be used in production!
## Error handling (>= v.2.6) ## Error handling (>= v2.6)
Currently the following error subclasses exist: Currently the following error subclasses exist:
@@ -398,27 +325,27 @@ All error classes are exported by the module.
Example: Example:
```js ```js
var redis = require('./'); var redis = require("./");
var assert = require('assert'); var assert = require("assert");
var client = redis.createClient(); var client = redis.createClient();
client.on('error', function(err) { client.on("error", function(err) {
assert(err instanceof Error); assert(err instanceof Error);
assert(err instanceof redis.AbortError); assert(err instanceof redis.AbortError);
assert(err instanceof redis.AggregateError); assert(err instanceof redis.AggregateError);
// The set and get get aggregated in here // The set and get get aggregated in here
assert.strictEqual(err.errors.length, 2); assert.strictEqual(err.errors.length, 2);
assert.strictEqual(err.code, 'NR_CLOSED'); assert.strictEqual(err.code, "NR_CLOSED");
}); });
client.set('foo', 123, 'bar', function(err, res) { client.set("foo", 123, "bar", function(err, res) {
// Too many arguments // Too many arguments
assert(err instanceof redis.ReplyError); // => true assert(err instanceof redis.ReplyError); // => true
assert.strictEqual(err.command, 'SET'); assert.strictEqual(err.command, "SET");
assert.deepStrictEqual(err.args, ['foo', 123, 'bar']); assert.deepStrictEqual(err.args, ["foo", 123, "bar"]);
redis.debug_mode = true; redis.debug_mode = true;
client.set('foo', 'bar'); client.set("foo", "bar");
client.get('foo'); client.get("foo");
process.nextTick(function() { process.nextTick(function() {
// Force closing the connection while the command did not yet return // Force closing the connection while the command did not yet return
client.end(true); client.end(true);
@@ -449,7 +376,7 @@ protocol. Any commands where client state is saved on the Redis server, e.g.
`*SUBSCRIBE` or the blocking `BL*` commands will _NOT_ work with `.unref()`. `*SUBSCRIBE` or the blocking `BL*` commands will _NOT_ work with `.unref()`.
```js ```js
var redis = require('redis'); var redis = require("redis");
var client = redis.createClient(); var client = redis.createClient();
/* /*
@@ -458,7 +385,7 @@ var client = redis.createClient();
client-server connection is alive. client-server connection is alive.
*/ */
client.unref(); client.unref();
client.get('foo', function(err, value) { client.get("foo", function(err, value) {
if (err) throw err; if (err) throw err;
console.log(value); console.log(value);
}); });
@@ -479,8 +406,8 @@ syntax.
Example: Example:
```js ```js
client.hmset('hosts', 'mjr', '1', 'another', '23', 'home', '1234'); client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234");
client.hgetall('hosts', function(err, obj) { client.hgetall("hosts", function(err, obj) {
console.dir(obj); console.dir(obj);
}); });
``` ```
@@ -491,8 +418,8 @@ Multiple values in a hash can be set by supplying an object:
```js ```js
client.HMSET(key2, { client.HMSET(key2, {
'0123456789': 'abcdefghij', // NOTE: key and value will be coerced to strings "0123456789": "abcdefghij", // NOTE: key and value will be coerced to strings
'some manner of key': 'a type of value', "some manner of key": "a type of value",
}); });
``` ```
@@ -504,7 +431,7 @@ Redis hash.
Multiple values may also be set by supplying a list: Multiple values may also be set by supplying a list:
```js ```js
client.HMSET(key1, '0123456789', 'abcdefghij', 'some manner of key', 'a type of value'); client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value");
``` ```
## Publish / Subscribe ## Publish / Subscribe
@@ -514,19 +441,19 @@ client connections, subscribes to a channel on one of them, and publishes to tha
channel on the other: channel on the other:
```js ```js
var redis = require('redis'); var redis = require("redis");
var sub = redis.createClient(), var sub = redis.createClient(),
pub = redis.createClient(); pub = redis.createClient();
var msg_count = 0; var msg_count = 0;
sub.on('subscribe', function(channel, count) { sub.on("subscribe", function(channel, count) {
pub.publish('a nice channel', 'I am sending a message.'); pub.publish("a nice channel", "I am sending a message.");
pub.publish('a nice channel', 'I am sending a second message.'); pub.publish("a nice channel", "I am sending a second message.");
pub.publish('a nice channel', 'I am sending my last message.'); pub.publish("a nice channel", "I am sending my last message.");
}); });
sub.on('message', function(channel, message) { sub.on("message", function(channel, message) {
console.log('sub channel ' + channel + ': ' + message); console.log("sub channel " + channel + ": " + message);
msg_count += 1; msg_count += 1;
if (msg_count === 3) { if (msg_count === 3) {
sub.unsubscribe(); sub.unsubscribe();
@@ -535,7 +462,7 @@ sub.on('message', function(channel, message) {
} }
}); });
sub.subscribe('a nice channel'); sub.subscribe("a nice channel");
``` ```
When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into
@@ -610,33 +537,33 @@ further information look at
[transactions](http://redis.io/topics/transactions)). [transactions](http://redis.io/topics/transactions)).
```js ```js
var redis = require('./index'), var redis = require("./index"),
client = redis.createClient(), client = redis.createClient(),
set_size = 20; set_size = 20;
client.sadd('bigset', 'a member'); client.sadd("bigset", "a member");
client.sadd('bigset', 'another member'); client.sadd("bigset", "another member");
while (set_size > 0) { while (set_size > 0) {
client.sadd('bigset', 'member ' + set_size); client.sadd("bigset", "member " + set_size);
set_size -= 1; set_size -= 1;
} }
// multi chain with an individual callback // multi chain with an individual callback
client client
.multi() .multi()
.scard('bigset') .scard("bigset")
.smembers('bigset') .smembers("bigset")
.keys('*', function(err, replies) { .keys("*", function(err, replies) {
// NOTE: code in this callback is NOT atomic // NOTE: code in this callback is NOT atomic
// this only happens after the the .exec call finishes. // this only happens after the the .exec call finishes.
client.mget(replies, redis.print); client.mget(replies, redis.print);
}) })
.dbsize() .dbsize()
.exec(function(err, replies) { .exec(function(err, replies) {
console.log('MULTI got ' + replies.length + ' replies'); console.log("MULTI got " + replies.length + " replies");
replies.forEach(function(reply, index) { replies.forEach(function(reply, index) {
console.log('Reply ' + index + ': ' + reply.toString()); console.log("Reply " + index + ": " + reply.toString());
}); });
}); });
``` ```
@@ -659,17 +586,17 @@ can queue individual commands while still sending regular client command as in
this example: this example:
```js ```js
var redis = require('redis'), var redis = require("redis"),
client = redis.createClient(), client = redis.createClient(),
multi; multi;
// start a separate multi command queue // start a separate multi command queue
multi = client.multi(); multi = client.multi();
multi.incr('incr thing', redis.print); multi.incr("incr thing", redis.print);
multi.incr('incr other thing', redis.print); multi.incr("incr other thing", redis.print);
// runs immediately // runs immediately
client.mset('incr thing', 100, 'incr other thing', 1, redis.print); client.mset("incr thing", 100, "incr other thing", 1, redis.print);
// drains multi queue and runs atomically // drains multi queue and runs atomically
multi.exec(function(err, replies) { multi.exec(function(err, replies) {
@@ -681,14 +608,14 @@ In addition to adding commands to the `MULTI` queue individually, you can also
pass an array of commands and arguments to the constructor: pass an array of commands and arguments to the constructor:
```js ```js
var redis = require('redis'), var redis = require("redis"),
client = redis.createClient(); client = redis.createClient();
client client
.multi([ .multi([
['mget', 'multifoo', 'multibar', redis.print], ["mget", "multifoo", "multibar", redis.print],
['incr', 'multifoo'], ["incr", "multifoo"],
['incr', 'multibar'], ["incr", "multibar"],
]) ])
.exec(function(err, replies) { .exec(function(err, replies) {
console.log(replies); console.log(replies);
@@ -853,14 +780,14 @@ arguments and the raw monitoring string.
Example: Example:
```js ```js
var client = require('redis').createClient(); var client = require("redis").createClient();
client.monitor(function(err, res) { client.monitor(function(err, res) {
console.log('Entering monitoring mode.'); console.log("Entering monitoring mode.");
}); });
client.set('foo', 'bar'); client.set("foo", "bar");
client.on('monitor', function(time, args, raw_reply) { client.on("monitor", function(time, args, raw_reply) {
console.log(time + ': ' + args); // 1458910076.446514:['set', 'foo', 'bar'] console.log(time + ": " + args); // 1458910076.446514:['set', 'foo', 'bar']
}); });
``` ```
@@ -886,12 +813,12 @@ easy comparison.
A handy callback function for displaying return values when testing. Example: A handy callback function for displaying return values when testing. Example:
```js ```js
var redis = require('redis'), var redis = require("redis"),
client = redis.createClient(); client = redis.createClient();
client.on('connect', function() { client.on("connect", function() {
client.set('foo_rand000000000000', 'some fantastic value', redis.print); client.set("foo_rand000000000000", "some fantastic value", redis.print);
client.get('foo_rand000000000000', redis.print); client.get("foo_rand000000000000", redis.print);
}); });
``` ```
@@ -908,12 +835,12 @@ To execute redis multi-word commands like `SCRIPT LOAD` or `CLIENT LIST` pass
the second word as first parameter: the second word as first parameter:
```js ```js
client.script('load', 'return 1'); client.script("load", "return 1");
client client
.multi() .multi()
.script('load', 'return 1') .script("load", "return 1")
.exec(); .exec();
client.multi([['script', 'load', 'return 1']]).exec(); client.multi([["script", "load", "return 1"]]).exec();
``` ```
## client.duplicate([options][, callback]) ## client.duplicate([options][, callback])
@@ -930,21 +857,21 @@ are used on the same redisClient instance as non-blocking commands, the
non-blocking ones may be queued up until after the blocking ones finish. non-blocking ones may be queued up until after the blocking ones finish.
```js ```js
var Redis = require('redis'); var Redis = require("redis");
var client = Redis.createClient(); var client = Redis.createClient();
var clientBlocking = client.duplicate(); var clientBlocking = client.duplicate();
var get = function() { var get = function() {
console.log('get called'); console.log("get called");
client.get('any_key', function() { client.get("any_key", function() {
console.log('get returned'); console.log("get returned");
}); });
setTimeout(get, 1000); setTimeout(get, 1000);
}; };
var brpop = function() { var brpop = function() {
console.log('brpop called'); console.log("brpop called");
clientBlocking.brpop('nonexistent', 5, function() { clientBlocking.brpop("nonexistent", 5, function() {
console.log('brpop return'); console.log("brpop return");
setTimeout(brpop, 1000); setTimeout(brpop, 1000);
}); });
}; };
@@ -994,16 +921,16 @@ This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset
Example: Example:
```js ```js
var args = ['myzset', 1, 'one', 2, 'two', 3, 'three', 99, 'ninety-nine']; var args = ["myzset", 1, "one", 2, "two", 3, "three", 99, "ninety-nine"];
client.zadd(args, function(err, response) { client.zadd(args, function(err, response) {
if (err) throw err; if (err) throw err;
console.log('added ' + response + ' items.'); console.log("added " + response + " items.");
// -Infinity and +Infinity also work // -Infinity and +Infinity also work
var args1 = ['myzset', '+inf', '-inf']; var args1 = ["myzset", "+inf", "-inf"];
client.zrevrangebyscore(args1, function(err, response) { client.zrevrangebyscore(args1, function(err, response) {
if (err) throw err; if (err) throw err;
console.log('example1', response); console.log("example1", response);
// write your code here // write your code here
}); });
@@ -1011,10 +938,10 @@ client.zadd(args, function(err, response) {
min = 1, min = 1,
offset = 1, offset = 1,
count = 2; count = 2;
var args2 = ['myzset', max, min, 'WITHSCORES', 'LIMIT', offset, count]; var args2 = ["myzset", max, min, "WITHSCORES", "LIMIT", offset, count];
client.zrevrangebyscore(args2, function(err, response) { client.zrevrangebyscore(args2, function(err, response) {
if (err) throw err; if (err) throw err;
console.log('example2', response); console.log("example2", response);
// write your code here // write your code here
}); });
}); });