ioredis 4.27.4 → 4.27.8
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/Changelog.md +28 -0
- package/README.md +1 -1
- package/built/autoPipelining.js +31 -8
- package/built/cluster/index.js +19 -0
- package/built/command.js +15 -1
- package/built/connectors/SentinelConnector/index.js +3 -0
- package/built/pipeline.js +3 -3
- package/built/redis/RedisOptions.js +1 -0
- package/built/redis/index.js +7 -0
- package/built/utils/lodash.js +2 -0
- package/package.json +3 -1
package/Changelog.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [4.27.8](https://github.com/luin/ioredis/compare/v4.27.7...v4.27.8) (2021-08-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* handle malicious keys for hgetall ([#1416](https://github.com/luin/ioredis/issues/1416)) ([7d73b9d](https://github.com/luin/ioredis/commit/7d73b9d07b52ec077f235292aa15c7aca203bba9)), closes [#1267](https://github.com/luin/ioredis/issues/1267)
|
|
7
|
+
|
|
8
|
+
## [4.27.7](https://github.com/luin/ioredis/compare/v4.27.6...v4.27.7) (2021-08-01)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **cluster:** fix autopipeline with keyPrefix or arg array ([#1391](https://github.com/luin/ioredis/issues/1391)) ([d7477aa](https://github.com/luin/ioredis/commit/d7477aa5853388b51037210542372131919ddfb2)), closes [#1264](https://github.com/luin/ioredis/issues/1264) [#1248](https://github.com/luin/ioredis/issues/1248) [#1392](https://github.com/luin/ioredis/issues/1392)
|
|
14
|
+
|
|
15
|
+
## [4.27.6](https://github.com/luin/ioredis/compare/v4.27.5...v4.27.6) (2021-06-13)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* fixed autopipeline performances. ([#1226](https://github.com/luin/ioredis/issues/1226)) ([42f1ee1](https://github.com/luin/ioredis/commit/42f1ee107174366a79ff94bec8a7a1ac353e035c))
|
|
21
|
+
|
|
22
|
+
## [4.27.5](https://github.com/luin/ioredis/compare/v4.27.4...v4.27.5) (2021-06-05)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* **SENTINEL:** actively failover detection under an option ([#1363](https://github.com/luin/ioredis/issues/1363)) ([f02e383](https://github.com/luin/ioredis/commit/f02e383996310adaefc2b4c40d946b76e450e5c7))
|
|
28
|
+
|
|
1
29
|
## [4.27.4](https://github.com/luin/ioredis/compare/v4.27.3...v4.27.4) (2021-06-04)
|
|
2
30
|
|
|
3
31
|
|
package/README.md
CHANGED
|
@@ -755,7 +755,7 @@ const redis = new Redis({
|
|
|
755
755
|
|
|
756
756
|
This feature is useful when using Amazon ElastiCache instances with Auto-failover disabled. On these instances, test your `reconnectOnError` handler by manually promoting the replica node to the primary role using the AWS console. The following writes fail with the error `READONLY`. Using `reconnectOnError`, we can force the connection to reconnect on this error in order to connect to the new master. Furthermore, if the `reconnectOnError` returns `2`, ioredis will resend the failed command after reconnecting.
|
|
757
757
|
|
|
758
|
-
On ElastiCache
|
|
758
|
+
On ElastiCache instances with Auto-failover enabled, `reconnectOnError` does not execute. Instead of returning a Redis error, AWS closes all connections to the master endpoint until the new primary node is ready. ioredis reconnects via `retryStrategy` instead of `reconnectOnError` after about a minute. On ElastiCache instances with Auto-failover enabled, test failover events with the `Failover primary` option in the AWS console.
|
|
759
759
|
|
|
760
760
|
## Connection Events
|
|
761
761
|
|
package/built/autoPipelining.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const PromiseContainer = require("./promiseContainer");
|
|
4
|
+
const lodash_1 = require("./utils/lodash");
|
|
4
5
|
const calculateSlot = require("cluster-key-slot");
|
|
5
6
|
const standard_as_callback_1 = require("standard-as-callback");
|
|
6
7
|
exports.kExec = Symbol("exec");
|
|
@@ -18,13 +19,6 @@ exports.notAllowedAutoPipelineCommands = [
|
|
|
18
19
|
"unsubscribe",
|
|
19
20
|
"unpsubscribe",
|
|
20
21
|
];
|
|
21
|
-
function findAutoPipeline(client, _commandName, ...args) {
|
|
22
|
-
if (!client.isCluster) {
|
|
23
|
-
return "main";
|
|
24
|
-
}
|
|
25
|
-
// We have slot information, we can improve routing by grouping slots served by the same subset of nodes
|
|
26
|
-
return client.slots[calculateSlot(args[0])].join(",");
|
|
27
|
-
}
|
|
28
22
|
function executeAutoPipeline(client, slotKey) {
|
|
29
23
|
/*
|
|
30
24
|
If a pipeline is already executing, keep queueing up commands
|
|
@@ -69,6 +63,29 @@ function shouldUseAutoPipelining(client, functionName, commandName) {
|
|
|
69
63
|
!client.options.autoPipeliningIgnoredCommands.includes(commandName));
|
|
70
64
|
}
|
|
71
65
|
exports.shouldUseAutoPipelining = shouldUseAutoPipelining;
|
|
66
|
+
/**
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
function getFirstValueInFlattenedArray(args) {
|
|
70
|
+
for (let i = 0; i < args.length; i++) {
|
|
71
|
+
const arg = args[i];
|
|
72
|
+
if (typeof arg === "string") {
|
|
73
|
+
return arg;
|
|
74
|
+
}
|
|
75
|
+
else if (Array.isArray(arg) || lodash_1.isArguments(arg)) {
|
|
76
|
+
if (arg.length === 0) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
return arg[0];
|
|
80
|
+
}
|
|
81
|
+
const flattened = lodash_1.flatten([arg]);
|
|
82
|
+
if (flattened.length > 0) {
|
|
83
|
+
return flattened[0];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
exports.getFirstValueInFlattenedArray = getFirstValueInFlattenedArray;
|
|
72
89
|
function executeWithAutoPipelining(client, functionName, commandName, args, callback) {
|
|
73
90
|
const CustomPromise = PromiseContainer.get();
|
|
74
91
|
// On cluster mode let's wait for slots to be available
|
|
@@ -83,7 +100,13 @@ function executeWithAutoPipelining(client, functionName, commandName, args, call
|
|
|
83
100
|
});
|
|
84
101
|
});
|
|
85
102
|
}
|
|
86
|
-
|
|
103
|
+
// If we have slot information, we can improve routing by grouping slots served by the same subset of nodes
|
|
104
|
+
// Note that the first value in args may be a (possibly empty) array.
|
|
105
|
+
// ioredis will only flatten one level of the array, in the Command constructor.
|
|
106
|
+
const prefix = client.options.keyPrefix || "";
|
|
107
|
+
const slotKey = client.isCluster
|
|
108
|
+
? client.slots[calculateSlot(`${prefix}${getFirstValueInFlattenedArray(args)}`)].join(",")
|
|
109
|
+
: "main";
|
|
87
110
|
if (!client._autoPipelines.has(slotKey)) {
|
|
88
111
|
const pipeline = client.pipeline();
|
|
89
112
|
pipeline[exports.kExec] = false;
|
package/built/cluster/index.js
CHANGED
|
@@ -42,6 +42,8 @@ class Cluster extends events_1.EventEmitter {
|
|
|
42
42
|
this.isRefreshing = false;
|
|
43
43
|
this.isCluster = true;
|
|
44
44
|
this._autoPipelines = new Map();
|
|
45
|
+
this._groupsIds = {};
|
|
46
|
+
this._groupsBySlot = Array(16384);
|
|
45
47
|
this._runningAutoPipelines = new Set();
|
|
46
48
|
this._readyDelayedCallbacks = [];
|
|
47
49
|
this._addedScriptHashes = {};
|
|
@@ -127,7 +129,9 @@ class Cluster extends events_1.EventEmitter {
|
|
|
127
129
|
reject(new Error("Redis is already connecting/connected"));
|
|
128
130
|
return;
|
|
129
131
|
}
|
|
132
|
+
// Make sure only one timer is active at a time
|
|
130
133
|
clearInterval(this._addedScriptHashesCleanInterval);
|
|
134
|
+
// Start the script cache cleaning
|
|
131
135
|
this._addedScriptHashesCleanInterval = setInterval(() => {
|
|
132
136
|
this._addedScriptHashes = {};
|
|
133
137
|
}, this.options.maxScriptsCachingTime);
|
|
@@ -491,6 +495,7 @@ class Cluster extends events_1.EventEmitter {
|
|
|
491
495
|
else {
|
|
492
496
|
_this.slots[slot] = [key];
|
|
493
497
|
}
|
|
498
|
+
_this._groupsBySlot[slot] = _this._groupsIds[_this.slots[slot].join(';')];
|
|
494
499
|
_this.connectionPool.findOrCreate(_this.natMapper(key));
|
|
495
500
|
tryConnection();
|
|
496
501
|
debug("refreshing slot caches... (triggered by MOVED error)");
|
|
@@ -693,6 +698,20 @@ class Cluster extends events_1.EventEmitter {
|
|
|
693
698
|
this.slots[slot] = keys;
|
|
694
699
|
}
|
|
695
700
|
}
|
|
701
|
+
// Assign to each node keys a numeric value to make autopipeline comparison faster.
|
|
702
|
+
this._groupsIds = Object.create(null);
|
|
703
|
+
let j = 0;
|
|
704
|
+
for (let i = 0; i < 16384; i++) {
|
|
705
|
+
const target = (this.slots[i] || []).join(';');
|
|
706
|
+
if (!target.length) {
|
|
707
|
+
this._groupsBySlot[i] = undefined;
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
if (!this._groupsIds[target]) {
|
|
711
|
+
this._groupsIds[target] = ++j;
|
|
712
|
+
}
|
|
713
|
+
this._groupsBySlot[i] = this._groupsIds[target];
|
|
714
|
+
}
|
|
696
715
|
this.connectionPool.reset(nodes);
|
|
697
716
|
callback();
|
|
698
717
|
}, this.options.slotsRefreshTimeout));
|
package/built/command.js
CHANGED
|
@@ -313,7 +313,21 @@ Command.setReplyTransformer("hgetall", function (result) {
|
|
|
313
313
|
if (Array.isArray(result)) {
|
|
314
314
|
const obj = {};
|
|
315
315
|
for (let i = 0; i < result.length; i += 2) {
|
|
316
|
-
|
|
316
|
+
const key = result[i];
|
|
317
|
+
const value = result[i + 1];
|
|
318
|
+
if (obj[key]) {
|
|
319
|
+
// can only be truthy if the property is special somehow, like '__proto__' or 'constructor'
|
|
320
|
+
// https://github.com/luin/ioredis/issues/1267
|
|
321
|
+
Object.defineProperty(obj, key, {
|
|
322
|
+
value,
|
|
323
|
+
configurable: true,
|
|
324
|
+
enumerable: true,
|
|
325
|
+
writable: true,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
obj[key] = value;
|
|
330
|
+
}
|
|
317
331
|
}
|
|
318
332
|
return obj;
|
|
319
333
|
}
|
|
@@ -205,6 +205,9 @@ class SentinelConnector extends AbstractConnector_1.default {
|
|
|
205
205
|
initFailoverDetector() {
|
|
206
206
|
var _a;
|
|
207
207
|
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
+
if (!this.options.failoverDetector) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
208
211
|
// Move the current sentinel to the first position
|
|
209
212
|
this.sentinelIterator.reset(true);
|
|
210
213
|
const sentinels = [];
|
package/built/pipeline.js
CHANGED
|
@@ -15,10 +15,9 @@ const commander_1 = require("./commander");
|
|
|
15
15
|
*/
|
|
16
16
|
function generateMultiWithNodes(redis, keys) {
|
|
17
17
|
const slot = calculateSlot(keys[0]);
|
|
18
|
-
const target = redis.
|
|
18
|
+
const target = redis._groupsBySlot[slot];
|
|
19
19
|
for (let i = 1; i < keys.length; i++) {
|
|
20
|
-
|
|
21
|
-
if (currentTarget !== target) {
|
|
20
|
+
if (redis._groupsBySlot[calculateSlot(keys[i])] !== target) {
|
|
22
21
|
return -1;
|
|
23
22
|
}
|
|
24
23
|
}
|
|
@@ -141,6 +140,7 @@ Pipeline.prototype.fillResult = function (value, position) {
|
|
|
141
140
|
moved: function (slot, key) {
|
|
142
141
|
_this.preferKey = key;
|
|
143
142
|
_this.redis.slots[errv[1]] = [key];
|
|
143
|
+
_this.redis._groupsBySlot[errv[1]] = _this.redis._groupsIds[_this.redis.slots[errv[1]].join(";")];
|
|
144
144
|
_this.redis.refreshSlotsCache();
|
|
145
145
|
_this.exec();
|
|
146
146
|
},
|
package/built/redis/index.js
CHANGED
|
@@ -93,6 +93,11 @@ const debug = utils_1.Debug("redis");
|
|
|
93
93
|
* @param {NatMap} [options.natMap=null] NAT map for sentinel connector.
|
|
94
94
|
* @param {boolean} [options.updateSentinels=true] - Update the given `sentinels` list with new IP
|
|
95
95
|
* addresses when communicating with existing sentinels.
|
|
96
|
+
* @param {boolean} [options.failoverDetector=false] - Detect failover actively by subscribing to the
|
|
97
|
+
* related channels. With this option disabled, ioredis is still able to detect failovers because Redis
|
|
98
|
+
* Sentinel will disconnect all clients whenever a failover happens, so ioredis will reconnect to the new
|
|
99
|
+
* master. This option is useful when you want to detect failover quicker, but it will create more TCP
|
|
100
|
+
* connections to Redis servers in order to subscribe to related channels.
|
|
96
101
|
* @param {boolean} [options.enableAutoPipelining=false] - When enabled, all commands issued during an event loop
|
|
97
102
|
* iteration are automatically wrapped in a pipeline and sent to the server at the same time.
|
|
98
103
|
* This can dramatically improve performance.
|
|
@@ -257,7 +262,9 @@ Redis.prototype.connect = function (callback) {
|
|
|
257
262
|
reject(new Error("Redis is already connecting/connected"));
|
|
258
263
|
return;
|
|
259
264
|
}
|
|
265
|
+
// Make sure only one timer is active at a time
|
|
260
266
|
clearInterval(this._addedScriptHashesCleanInterval);
|
|
267
|
+
// Start the script cache cleaning
|
|
261
268
|
this._addedScriptHashesCleanInterval = setInterval(() => {
|
|
262
269
|
this._addedScriptHashes = {};
|
|
263
270
|
}, this.options.maxScriptsCachingTime);
|
package/built/utils/lodash.js
CHANGED
|
@@ -4,5 +4,7 @@ const defaults = require("lodash.defaults");
|
|
|
4
4
|
exports.defaults = defaults;
|
|
5
5
|
const flatten = require("lodash.flatten");
|
|
6
6
|
exports.flatten = flatten;
|
|
7
|
+
const isArguments = require("lodash.isarguments");
|
|
8
|
+
exports.isArguments = isArguments;
|
|
7
9
|
function noop() { }
|
|
8
10
|
exports.noop = noop;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ioredis",
|
|
3
|
-
"version": "4.27.
|
|
3
|
+
"version": "4.27.8",
|
|
4
4
|
"description": "A robust, performance-focused and full-featured Redis client for Node.js.",
|
|
5
5
|
"main": "built/index.js",
|
|
6
6
|
"files": [
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"denque": "^1.1.0",
|
|
39
39
|
"lodash.defaults": "^4.2.0",
|
|
40
40
|
"lodash.flatten": "^4.4.0",
|
|
41
|
+
"lodash.isarguments": "^3.1.0",
|
|
41
42
|
"p-map": "^2.1.0",
|
|
42
43
|
"redis-commands": "1.7.0",
|
|
43
44
|
"redis-errors": "^1.2.0",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"@types/debug": "^4.1.5",
|
|
54
55
|
"@types/lodash.defaults": "^4.2.6",
|
|
55
56
|
"@types/lodash.flatten": "^4.4.6",
|
|
57
|
+
"@types/lodash.isarguments": "^3.1.6",
|
|
56
58
|
"@types/mocha": "^7.0.2",
|
|
57
59
|
"@types/node": "^13.11.0",
|
|
58
60
|
"@types/redis-errors": "1.2.0",
|