ioredis 4.27.1 → 4.27.5

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 CHANGED
@@ -1,3 +1,31 @@
1
+ ## [4.27.5](https://github.com/luin/ioredis/compare/v4.27.4...v4.27.5) (2021-06-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **SENTINEL:** actively failover detection under an option ([#1363](https://github.com/luin/ioredis/issues/1363)) ([f02e383](https://github.com/luin/ioredis/commit/f02e383996310adaefc2b4c40d946b76e450e5c7))
7
+
8
+ ## [4.27.4](https://github.com/luin/ioredis/compare/v4.27.3...v4.27.4) (2021-06-04)
9
+
10
+
11
+ ### Performance Improvements
12
+
13
+ * Serialize error stack only when needed ([#1359](https://github.com/luin/ioredis/issues/1359)) ([62b6a64](https://github.com/luin/ioredis/commit/62b6a648910eccc3d83a3acd2db873704fd2080a))
14
+
15
+ ## [4.27.3](https://github.com/luin/ioredis/compare/v4.27.2...v4.27.3) (2021-05-22)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * autopipeling for buffer function ([#1231](https://github.com/luin/ioredis/issues/1231)) ([abd9a82](https://github.com/luin/ioredis/commit/abd9a82433ad67b91a4bddb45aff8da2e20d45e8))
21
+
22
+ ## [4.27.2](https://github.com/luin/ioredis/compare/v4.27.1...v4.27.2) (2021-05-04)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * **cluster:** avoid ClusterAllFailedError in certain cases ([aa9c5b1](https://github.com/luin/ioredis/commit/aa9c5b1fee5daa24f35b3ff0d3556ecfb86db251)), closes [#1330](https://github.com/luin/ioredis/issues/1330)
28
+
1
29
  ## [4.27.1](https://github.com/luin/ioredis/compare/v4.27.0...v4.27.1) (2021-04-24)
2
30
 
3
31
 
@@ -61,14 +61,15 @@ function executeAutoPipeline(client, slotKey) {
61
61
  }
62
62
  });
63
63
  }
64
- function shouldUseAutoPipelining(client, commandName) {
65
- return (client.options.enableAutoPipelining &&
64
+ function shouldUseAutoPipelining(client, functionName, commandName) {
65
+ return (functionName &&
66
+ client.options.enableAutoPipelining &&
66
67
  !client.isPipeline &&
67
68
  !exports.notAllowedAutoPipelineCommands.includes(commandName) &&
68
69
  !client.options.autoPipeliningIgnoredCommands.includes(commandName));
69
70
  }
70
71
  exports.shouldUseAutoPipelining = shouldUseAutoPipelining;
71
- function executeWithAutoPipelining(client, commandName, args, callback) {
72
+ function executeWithAutoPipelining(client, functionName, commandName, args, callback) {
72
73
  const CustomPromise = PromiseContainer.get();
73
74
  // On cluster mode let's wait for slots to be available
74
75
  if (client.isCluster && !client.slots.length) {
@@ -78,7 +79,7 @@ function executeWithAutoPipelining(client, commandName, args, callback) {
78
79
  reject(err);
79
80
  return;
80
81
  }
81
- executeWithAutoPipelining(client, commandName, args, callback).then(resolve, reject);
82
+ executeWithAutoPipelining(client, functionName, commandName, args, callback).then(resolve, reject);
82
83
  });
83
84
  });
84
85
  }
@@ -112,7 +113,7 @@ function executeWithAutoPipelining(client, commandName, args, callback) {
112
113
  }
113
114
  resolve(value);
114
115
  });
115
- pipeline[commandName](...args);
116
+ pipeline[functionName](...args);
116
117
  });
117
118
  return standard_as_callback_1.default(autoPipelinePromise, callback);
118
119
  }
@@ -185,7 +185,12 @@ class Cluster extends events_1.EventEmitter {
185
185
  this.once("refresh", refreshListener);
186
186
  this.once("close", closeListener);
187
187
  this.once("close", this.handleCloseEvent.bind(this));
188
- this.refreshSlotsCache();
188
+ this.refreshSlotsCache(function (err) {
189
+ if (err && err.message === "Failed to refresh slots cache.") {
190
+ redis_1.default.prototype.silentEmit.call(this, "error", err);
191
+ this.connectionPool.reset([]);
192
+ }
193
+ }.bind(this));
189
194
  this.subscriber.start();
190
195
  })
191
196
  .catch((err) => {
@@ -385,8 +390,6 @@ class Cluster extends events_1.EventEmitter {
385
390
  function tryNode(index) {
386
391
  if (index === nodes.length) {
387
392
  const error = new ClusterAllFailedError_1.default("Failed to refresh slots cache.", lastNodeError);
388
- redis_1.default.prototype.silentEmit.call(_this, "error", error);
389
- _this.connectionPool.reset([]);
390
393
  return wrapper(error);
391
394
  }
392
395
  const node = nodes[index];
package/built/command.js CHANGED
@@ -101,7 +101,7 @@ class Command {
101
101
  this.resolve = this._convertValue(resolve);
102
102
  if (this.errorStack) {
103
103
  this.reject = (err) => {
104
- reject(utils_1.optimizeErrorStack(err, this.errorStack, __dirname));
104
+ reject(utils_1.optimizeErrorStack(err, this.errorStack.stack, __dirname));
105
105
  };
106
106
  }
107
107
  else {
@@ -23,6 +23,7 @@ function Commander() {
23
23
  showFriendlyErrorStack: false,
24
24
  });
25
25
  this.scriptsSet = {};
26
+ this.addedBuiltinSet = new Set();
26
27
  }
27
28
  exports.default = Commander;
28
29
  const commands = require("redis-commands").list.filter(function (command) {
@@ -47,16 +48,28 @@ Commander.prototype.getBuiltinCommands = function () {
47
48
  */
48
49
  Commander.prototype.createBuiltinCommand = function (commandName) {
49
50
  return {
50
- string: generateFunction(commandName, "utf8"),
51
- buffer: generateFunction(commandName, null),
51
+ string: generateFunction(null, commandName, "utf8"),
52
+ buffer: generateFunction(null, commandName, null),
52
53
  };
53
54
  };
55
+ /**
56
+ * Create add builtin command
57
+ *
58
+ * @param {string} commandName - command name
59
+ * @return {object} functions
60
+ * @public
61
+ */
62
+ Commander.prototype.addBuiltinCommand = function (commandName) {
63
+ this.addedBuiltinSet.add(commandName);
64
+ this[commandName] = generateFunction(commandName, commandName, "utf8");
65
+ this[commandName + "Buffer"] = generateFunction(commandName + "Buffer", commandName, null);
66
+ };
54
67
  commands.forEach(function (commandName) {
55
- Commander.prototype[commandName] = generateFunction(commandName, "utf8");
56
- Commander.prototype[commandName + "Buffer"] = generateFunction(commandName, null);
68
+ Commander.prototype[commandName] = generateFunction(commandName, commandName, "utf8");
69
+ Commander.prototype[commandName + "Buffer"] = generateFunction(commandName + "Buffer", commandName, null);
57
70
  });
58
- Commander.prototype.call = generateFunction("utf8");
59
- Commander.prototype.callBuffer = generateFunction(null);
71
+ Commander.prototype.call = generateFunction("call", "utf8");
72
+ Commander.prototype.callBuffer = generateFunction("callBuffer", null);
60
73
  // eslint-disable-next-line @typescript-eslint/camelcase
61
74
  Commander.prototype.send_command = Commander.prototype.call;
62
75
  /**
@@ -72,8 +85,8 @@ Commander.prototype.send_command = Commander.prototype.call;
72
85
  Commander.prototype.defineCommand = function (name, definition) {
73
86
  const script = new script_1.default(definition.lua, definition.numberOfKeys, this.options.keyPrefix, definition.readOnly);
74
87
  this.scriptsSet[name] = script;
75
- this[name] = generateScriptingFunction(name, script, "utf8");
76
- this[name + "Buffer"] = generateScriptingFunction(name, script, null);
88
+ this[name] = generateScriptingFunction(name, name, script, "utf8");
89
+ this[name + "Buffer"] = generateScriptingFunction(name + "Buffer", name, script, null);
77
90
  };
78
91
  /**
79
92
  * Send a command
@@ -82,7 +95,7 @@ Commander.prototype.defineCommand = function (name, definition) {
82
95
  * @public
83
96
  */
84
97
  Commander.prototype.sendCommand = function () { };
85
- function generateFunction(_commandName, _encoding) {
98
+ function generateFunction(functionName, _commandName, _encoding) {
86
99
  if (typeof _encoding === "undefined") {
87
100
  _encoding = _commandName;
88
101
  _commandName = null;
@@ -97,9 +110,7 @@ function generateFunction(_commandName, _encoding) {
97
110
  callback = undefined;
98
111
  }
99
112
  const options = {
100
- errorStack: this.options.showFriendlyErrorStack
101
- ? new Error().stack
102
- : undefined,
113
+ errorStack: this.options.showFriendlyErrorStack ? new Error() : undefined,
103
114
  keyPrefix: this.options.keyPrefix,
104
115
  replyEncoding: _encoding,
105
116
  };
@@ -107,14 +118,14 @@ function generateFunction(_commandName, _encoding) {
107
118
  return standard_as_callback_1.default(PromiseContainer.get().reject(new Error(DROP_BUFFER_SUPPORT_ERROR)), callback);
108
119
  }
109
120
  // No auto pipeline, use regular command sending
110
- if (!autoPipelining_1.shouldUseAutoPipelining(this, commandName)) {
121
+ if (!autoPipelining_1.shouldUseAutoPipelining(this, functionName, commandName)) {
111
122
  return this.sendCommand(new command_1.default(commandName, args, options, callback));
112
123
  }
113
124
  // Create a new pipeline and make sure it's scheduled
114
- return autoPipelining_1.executeWithAutoPipelining(this, commandName, args, callback);
125
+ return autoPipelining_1.executeWithAutoPipelining(this, functionName, commandName, args, callback);
115
126
  };
116
127
  }
117
- function generateScriptingFunction(name, script, encoding) {
128
+ function generateScriptingFunction(functionName, commandName, script, encoding) {
118
129
  return function () {
119
130
  let length = arguments.length;
120
131
  const lastArgIndex = length - 1;
@@ -140,13 +151,13 @@ function generateScriptingFunction(name, script, encoding) {
140
151
  options = { replyEncoding: encoding };
141
152
  }
142
153
  if (this.options.showFriendlyErrorStack) {
143
- options.errorStack = new Error().stack;
154
+ options.errorStack = new Error();
144
155
  }
145
156
  // No auto pipeline, use regular command sending
146
- if (!autoPipelining_1.shouldUseAutoPipelining(this, name)) {
157
+ if (!autoPipelining_1.shouldUseAutoPipelining(this, functionName, commandName)) {
147
158
  return script.execute(this, args, options, callback);
148
159
  }
149
160
  // Create a new pipeline and make sure it's scheduled
150
- return autoPipelining_1.executeWithAutoPipelining(this, name, args, callback);
161
+ return autoPipelining_1.executeWithAutoPipelining(this, functionName, commandName, args, callback);
151
162
  };
152
163
  }
@@ -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
@@ -41,6 +41,10 @@ function Pipeline(redis) {
41
41
  this[name] = redis[name];
42
42
  this[name + "Buffer"] = redis[name + "Buffer"];
43
43
  });
44
+ redis.addedBuiltinSet.forEach((name) => {
45
+ this[name] = redis[name];
46
+ this[name + "Buffer"] = redis[name + "Buffer"];
47
+ });
44
48
  const Promise = PromiseContainer.get();
45
49
  this.promise = new Promise((resolve, reject) => {
46
50
  this.resolve = resolve;
@@ -31,6 +31,7 @@ exports.DEFAULT_REDIS_OPTIONS = {
31
31
  natMap: null,
32
32
  enableTLSForSentinelMode: false,
33
33
  updateSentinels: true,
34
+ failoverDetector: false,
34
35
  // Status
35
36
  username: null,
36
37
  password: null,
@@ -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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ioredis",
3
- "version": "4.27.1",
3
+ "version": "4.27.5",
4
4
  "description": "A robust, performance-focused and full-featured Redis client for Node.js.",
5
5
  "main": "built/index.js",
6
6
  "files": [