ioredis 4.24.4 → 4.26.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/Changelog.md +33 -0
- package/README.md +32 -4
- package/built/cluster/ClusterSubscriber.js +8 -3
- package/built/cluster/index.js +1 -1
- package/built/cluster/util.js +5 -0
- package/built/command.js +2 -0
- package/built/connectors/AbstractConnector.js +11 -2
- package/built/connectors/SentinelConnector/index.js +104 -99
- package/built/connectors/StandaloneConnector.js +1 -1
- package/built/redis/RedisOptions.js +1 -0
- package/built/redis/event_handler.js +5 -1
- package/built/redis/index.js +7 -0
- package/package.json +4 -4
package/Changelog.md
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
# [4.26.0](https://github.com/luin/ioredis/compare/v4.25.0...v4.26.0) (2021-04-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **cluster:** subscriber connection leaks ([81b9be0](https://github.com/luin/ioredis/commit/81b9be021d471796bba00ee7b08768df9d7e2689)), closes [#1325](https://github.com/luin/ioredis/issues/1325)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **cluster:** apply provided connection name to internal connections ([2e388db](https://github.com/luin/ioredis/commit/2e388dbaa528d009b97b82c4dc362377165670a4))
|
|
12
|
+
|
|
13
|
+
# [4.25.0](https://github.com/luin/ioredis/compare/v4.24.6...v4.25.0) (2021-04-02)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* added commandTimeout option ([#1320](https://github.com/luin/ioredis/issues/1320)) ([56f0272](https://github.com/luin/ioredis/commit/56f02729958545e5b7e713436181b0dd46f8803a))
|
|
19
|
+
|
|
20
|
+
## [4.24.6](https://github.com/luin/ioredis/compare/v4.24.5...v4.24.6) (2021-03-31)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* force disconnect after a timeout if socket is still half-open ([#1318](https://github.com/luin/ioredis/issues/1318)) ([6cacd17](https://github.com/luin/ioredis/commit/6cacd17e6ac4d9f995728ee09777e0a7f3b739d7))
|
|
26
|
+
|
|
27
|
+
## [4.24.5](https://github.com/luin/ioredis/compare/v4.24.4...v4.24.5) (2021-03-27)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
* select db in cluster mode causes unhandled errors ([#1311](https://github.com/luin/ioredis/issues/1311)) ([da3ec92](https://github.com/luin/ioredis/commit/da3ec92a406ab6c2f1517810f29f55a0c12712dc)), closes [#1310](https://github.com/luin/ioredis/issues/1310)
|
|
33
|
+
|
|
1
34
|
## [4.24.4](https://github.com/luin/ioredis/compare/v4.24.3...v4.24.4) (2021-03-24)
|
|
2
35
|
|
|
3
36
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
A robust, performance-focused and full-featured [Redis](http://redis.io) client for [Node.js](https://nodejs.org).
|
|
13
13
|
|
|
14
|
-
Supports Redis >= 2.6.12 and (Node.js >= 6).
|
|
14
|
+
Supports Redis >= 2.6.12 and (Node.js >= 6). Completely compatible with Redis 6.x.
|
|
15
15
|
|
|
16
16
|
# Features
|
|
17
17
|
|
|
@@ -206,12 +206,12 @@ It worth noticing that a connection (aka `Redis` instance) can't play both roles
|
|
|
206
206
|
If you want to do pub/sub in the same file/process, you should create a separate connection:
|
|
207
207
|
|
|
208
208
|
```javascript
|
|
209
|
-
const Redis = require(
|
|
209
|
+
const Redis = require("ioredis");
|
|
210
210
|
const sub = new Redis();
|
|
211
211
|
const pub = new Redis();
|
|
212
212
|
|
|
213
213
|
sub.subscribe(/* ... */); // From now, `sub` enters the subscriber mode.
|
|
214
|
-
sub.on("message"
|
|
214
|
+
sub.on("message" /* ... */);
|
|
215
215
|
|
|
216
216
|
setInterval(() => {
|
|
217
217
|
// `pub` can be used to publish messages, or send other regular commands (e.g. `hgetall`)
|
|
@@ -230,6 +230,34 @@ redis.on("pmessage", (pattern, channel, message) => {});
|
|
|
230
230
|
redis.on("pmessageBuffer", (pattern, channel, message) => {});
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
+
## Streams
|
|
234
|
+
|
|
235
|
+
Redis v5 introduces a new data type called streams. It doubles as a communication channel for building streaming architectures and as a log-like data structure for persisting data. With ioredis, the usage can be pretty straightforward. Say we have a producer publishes messages to a stream with `redis.xadd("mystream", "*", "randomValue", Math.random())` (You may find the [official documentation of Streams](https://redis.io/topics/streams-intro) as a starter to understand the parameters used), to consume the messages, we'll have a consumer with the following code:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
const Redis = require("ioredis");
|
|
239
|
+
const redis = new Redis();
|
|
240
|
+
|
|
241
|
+
const processMessage = (message) => {
|
|
242
|
+
console.log("Id: %s. Data: %O", message[0], message[1]);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
async function listenForMessage(lastId = "$") {
|
|
246
|
+
// `results` is an array, each element of which corresponds to a key.
|
|
247
|
+
// Because we only listen to one key (mystream) here, `results` only contains
|
|
248
|
+
// a single element. See more: https://redis.io/commands/xread#return-value
|
|
249
|
+
const results = await redis.xread("block", 0, "STREAMS", "mystream", lastId);
|
|
250
|
+
const [key, messages] = results[0]; // `key` equals to "mystream"
|
|
251
|
+
|
|
252
|
+
messages.forEach(processMessage);
|
|
253
|
+
|
|
254
|
+
// Pass the last id of the results to the next round.
|
|
255
|
+
await listenForMessage(messages[messages.length - 1][0]);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
listenForMessage();
|
|
259
|
+
```
|
|
260
|
+
|
|
233
261
|
## Handle Binary Data
|
|
234
262
|
|
|
235
263
|
Arguments can be buffers:
|
|
@@ -741,7 +769,7 @@ The Redis instance will emit some events about the state of the connection to th
|
|
|
741
769
|
| close | emits when an established Redis server connection has closed. |
|
|
742
770
|
| reconnecting | emits after `close` when a reconnection will be made. The argument of the event is the time (in ms) before reconnecting. |
|
|
743
771
|
| end | emits after `close` when no more reconnections will be made, or the connection is failed to establish. |
|
|
744
|
-
| wait
|
|
772
|
+
| wait | emits when `lazyConnect` is set and will wait for the first command to be called before connecting. |
|
|
745
773
|
|
|
746
774
|
You can also check out the `Redis#status` property to get the current connection status.
|
|
747
775
|
|
|
@@ -4,7 +4,6 @@ const util_1 = require("./util");
|
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
5
|
const redis_1 = require("../redis");
|
|
6
6
|
const debug = utils_1.Debug("cluster:subscriber");
|
|
7
|
-
const SUBSCRIBER_CONNECTION_NAME = "ioredisClusterSubscriber";
|
|
8
7
|
class ClusterSubscriber {
|
|
9
8
|
constructor(connectionPool, emitter) {
|
|
10
9
|
this.connectionPool = connectionPool;
|
|
@@ -38,6 +37,9 @@ class ClusterSubscriber {
|
|
|
38
37
|
if (lastActiveSubscriber) {
|
|
39
38
|
lastActiveSubscriber.disconnect();
|
|
40
39
|
}
|
|
40
|
+
if (this.subscriber) {
|
|
41
|
+
this.subscriber.disconnect();
|
|
42
|
+
}
|
|
41
43
|
const sampleNode = utils_1.sample(this.connectionPool.getNodes());
|
|
42
44
|
if (!sampleNode) {
|
|
43
45
|
debug("selecting subscriber failed since there is no node discovered in the cluster yet");
|
|
@@ -61,7 +63,7 @@ class ClusterSubscriber {
|
|
|
61
63
|
username: options.username,
|
|
62
64
|
password: options.password,
|
|
63
65
|
enableReadyCheck: true,
|
|
64
|
-
connectionName:
|
|
66
|
+
connectionName: util_1.getConnectionName("subscriber", options.connectionName),
|
|
65
67
|
lazyConnect: true,
|
|
66
68
|
tls: options.tls,
|
|
67
69
|
});
|
|
@@ -90,7 +92,10 @@ class ClusterSubscriber {
|
|
|
90
92
|
this.lastActiveSubscriber = this.subscriber;
|
|
91
93
|
}
|
|
92
94
|
})
|
|
93
|
-
.catch(
|
|
95
|
+
.catch(() => {
|
|
96
|
+
// TODO: should probably disconnect the subscriber and try again.
|
|
97
|
+
debug("failed to %s %d channels", type, channels.length);
|
|
98
|
+
});
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
}
|
package/built/cluster/index.js
CHANGED
|
@@ -652,7 +652,7 @@ class Cluster extends events_1.EventEmitter {
|
|
|
652
652
|
enableOfflineQueue: true,
|
|
653
653
|
enableReadyCheck: false,
|
|
654
654
|
retryStrategy: null,
|
|
655
|
-
connectionName: "
|
|
655
|
+
connectionName: util_1.getConnectionName("refresher", this.options.redisOptions && this.options.redisOptions.connectionName),
|
|
656
656
|
});
|
|
657
657
|
// Ignore error events since we will handle
|
|
658
658
|
// exceptions for the CLUSTER SLOTS command.
|
package/built/cluster/util.js
CHANGED
|
@@ -92,3 +92,8 @@ function weightSrvRecords(recordsGroup) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
exports.weightSrvRecords = weightSrvRecords;
|
|
95
|
+
function getConnectionName(component, nodeConnectionName) {
|
|
96
|
+
const prefix = `ioredis-cluster(${component})`;
|
|
97
|
+
return nodeConnectionName ? `${prefix}:${nodeConnectionName}` : prefix;
|
|
98
|
+
}
|
|
99
|
+
exports.getConnectionName = getConnectionName;
|
package/built/command.js
CHANGED
|
@@ -46,6 +46,7 @@ class Command {
|
|
|
46
46
|
this.transformed = false;
|
|
47
47
|
this.isCustomCommand = false;
|
|
48
48
|
this.inTransaction = false;
|
|
49
|
+
this.isResolved = false;
|
|
49
50
|
this.replyEncoding = options.replyEncoding;
|
|
50
51
|
this.errorStack = options.errorStack;
|
|
51
52
|
this.args = lodash_1.flatten(args);
|
|
@@ -220,6 +221,7 @@ class Command {
|
|
|
220
221
|
return (value) => {
|
|
221
222
|
try {
|
|
222
223
|
resolve(this.transformReply(value));
|
|
224
|
+
this.isResolved = true;
|
|
223
225
|
}
|
|
224
226
|
catch (err) {
|
|
225
227
|
this.reject(err);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const debug = utils_1.Debug("AbstractConnector");
|
|
3
5
|
class AbstractConnector {
|
|
4
|
-
constructor() {
|
|
6
|
+
constructor(disconnectTimeout) {
|
|
5
7
|
this.connecting = false;
|
|
8
|
+
this.disconnectTimeout = disconnectTimeout;
|
|
6
9
|
}
|
|
7
10
|
check(info) {
|
|
8
11
|
return true;
|
|
@@ -10,7 +13,13 @@ class AbstractConnector {
|
|
|
10
13
|
disconnect() {
|
|
11
14
|
this.connecting = false;
|
|
12
15
|
if (this.stream) {
|
|
13
|
-
this.stream
|
|
16
|
+
const stream = this.stream; // Make sure callbacks refer to the same instance
|
|
17
|
+
const timeout = setTimeout(() => {
|
|
18
|
+
debug("stream %s:%s still open, destroying it", stream.remoteAddress, stream.remotePort);
|
|
19
|
+
stream.destroy();
|
|
20
|
+
}, this.disconnectTimeout);
|
|
21
|
+
stream.on("close", () => clearTimeout(timeout));
|
|
22
|
+
stream.end();
|
|
14
23
|
}
|
|
15
24
|
}
|
|
16
25
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
const net_1 = require("net");
|
|
4
13
|
const utils_1 = require("../../utils");
|
|
@@ -11,7 +20,7 @@ const redis_1 = require("../../redis");
|
|
|
11
20
|
const debug = utils_1.Debug("SentinelConnector");
|
|
12
21
|
class SentinelConnector extends AbstractConnector_1.default {
|
|
13
22
|
constructor(options) {
|
|
14
|
-
super();
|
|
23
|
+
super(options.disconnectTimeout);
|
|
15
24
|
this.options = options;
|
|
16
25
|
if (!this.options.sentinels.length) {
|
|
17
26
|
throw new Error("Requires at least one sentinel to connect to.");
|
|
@@ -38,7 +47,7 @@ class SentinelConnector extends AbstractConnector_1.default {
|
|
|
38
47
|
this.connecting = true;
|
|
39
48
|
this.retryAttempts = 0;
|
|
40
49
|
let lastError;
|
|
41
|
-
const connectToNext = () =>
|
|
50
|
+
const connectToNext = () => __awaiter(this, void 0, void 0, function* () {
|
|
42
51
|
const endpoint = this.sentinelIterator.next();
|
|
43
52
|
if (endpoint.done) {
|
|
44
53
|
this.sentinelIterator.reset(false);
|
|
@@ -54,69 +63,69 @@ class SentinelConnector extends AbstractConnector_1.default {
|
|
|
54
63
|
debug(errorMsg);
|
|
55
64
|
const error = new Error(errorMsg);
|
|
56
65
|
if (typeof retryDelay === "number") {
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
resolve(connectToNext());
|
|
59
|
-
}, retryDelay);
|
|
60
66
|
eventEmitter("error", error);
|
|
67
|
+
yield new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
68
|
+
return connectToNext();
|
|
61
69
|
}
|
|
62
70
|
else {
|
|
63
|
-
|
|
71
|
+
throw error;
|
|
64
72
|
}
|
|
65
|
-
return;
|
|
66
73
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
this.sentinelIterator.reset(true);
|
|
85
|
-
resolve(this.stream);
|
|
74
|
+
let resolved = null;
|
|
75
|
+
let err = null;
|
|
76
|
+
try {
|
|
77
|
+
resolved = yield this.resolve(endpoint.value);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
err = error;
|
|
81
|
+
}
|
|
82
|
+
if (!this.connecting) {
|
|
83
|
+
throw new Error(utils_1.CONNECTION_CLOSED_ERROR_MSG);
|
|
84
|
+
}
|
|
85
|
+
if (resolved) {
|
|
86
|
+
debug("resolved: %s:%s", resolved.host, resolved.port);
|
|
87
|
+
if (this.options.enableTLSForSentinelMode && this.options.tls) {
|
|
88
|
+
Object.assign(resolved, this.options.tls);
|
|
89
|
+
this.stream = tls_1.connect(resolved);
|
|
86
90
|
}
|
|
87
91
|
else {
|
|
88
|
-
|
|
89
|
-
const errorMsg = err
|
|
90
|
-
? "failed to connect to sentinel " +
|
|
91
|
-
endpointAddress +
|
|
92
|
-
" because " +
|
|
93
|
-
err.message
|
|
94
|
-
: "connected to sentinel " +
|
|
95
|
-
endpointAddress +
|
|
96
|
-
" successfully, but got an invalid reply: " +
|
|
97
|
-
resolved;
|
|
98
|
-
debug(errorMsg);
|
|
99
|
-
eventEmitter("sentinelError", new Error(errorMsg));
|
|
100
|
-
if (err) {
|
|
101
|
-
lastError = err;
|
|
102
|
-
}
|
|
103
|
-
resolve(connectToNext());
|
|
92
|
+
this.stream = net_1.createConnection(resolved);
|
|
104
93
|
}
|
|
105
|
-
|
|
94
|
+
this.stream.once("error", (err) => {
|
|
95
|
+
this.firstError = err;
|
|
96
|
+
});
|
|
97
|
+
this.sentinelIterator.reset(true);
|
|
98
|
+
return this.stream;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const endpointAddress = endpoint.value.host + ":" + endpoint.value.port;
|
|
102
|
+
const errorMsg = err
|
|
103
|
+
? "failed to connect to sentinel " +
|
|
104
|
+
endpointAddress +
|
|
105
|
+
" because " +
|
|
106
|
+
err.message
|
|
107
|
+
: "connected to sentinel " +
|
|
108
|
+
endpointAddress +
|
|
109
|
+
" successfully, but got an invalid reply: " +
|
|
110
|
+
resolved;
|
|
111
|
+
debug(errorMsg);
|
|
112
|
+
eventEmitter("sentinelError", new Error(errorMsg));
|
|
113
|
+
if (err) {
|
|
114
|
+
lastError = err;
|
|
115
|
+
}
|
|
116
|
+
return connectToNext();
|
|
117
|
+
}
|
|
106
118
|
});
|
|
107
119
|
return connectToNext();
|
|
108
120
|
}
|
|
109
|
-
updateSentinels(client
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
client.sentinel("sentinels", this.options.name, (err, result) => {
|
|
114
|
-
if (err) {
|
|
115
|
-
client.disconnect();
|
|
116
|
-
return callback(err);
|
|
121
|
+
updateSentinels(client) {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
if (!this.options.updateSentinels) {
|
|
124
|
+
return;
|
|
117
125
|
}
|
|
126
|
+
const result = yield client.sentinel("sentinels", this.options.name);
|
|
118
127
|
if (!Array.isArray(result)) {
|
|
119
|
-
return
|
|
128
|
+
return;
|
|
120
129
|
}
|
|
121
130
|
result
|
|
122
131
|
.map(utils_1.packObject)
|
|
@@ -132,39 +141,27 @@ class SentinelConnector extends AbstractConnector_1.default {
|
|
|
132
141
|
}
|
|
133
142
|
});
|
|
134
143
|
debug("Updated internal sentinels: %s", this.sentinelIterator);
|
|
135
|
-
callback(null);
|
|
136
144
|
});
|
|
137
145
|
}
|
|
138
|
-
resolveMaster(client
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
client.disconnect();
|
|
146
|
-
if (err) {
|
|
147
|
-
return callback(err);
|
|
148
|
-
}
|
|
149
|
-
callback(null, this.sentinelNatResolve(Array.isArray(result)
|
|
150
|
-
? { host: result[0], port: Number(result[1]) }
|
|
151
|
-
: null));
|
|
152
|
-
});
|
|
146
|
+
resolveMaster(client) {
|
|
147
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
const result = yield client.sentinel("get-master-addr-by-name", this.options.name);
|
|
149
|
+
yield this.updateSentinels(client);
|
|
150
|
+
return this.sentinelNatResolve(Array.isArray(result)
|
|
151
|
+
? { host: result[0], port: Number(result[1]) }
|
|
152
|
+
: null);
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
|
-
resolveSlave(client
|
|
156
|
-
|
|
157
|
-
client.
|
|
158
|
-
if (err) {
|
|
159
|
-
return callback(err);
|
|
160
|
-
}
|
|
155
|
+
resolveSlave(client) {
|
|
156
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
157
|
+
const result = yield client.sentinel("slaves", this.options.name);
|
|
161
158
|
if (!Array.isArray(result)) {
|
|
162
|
-
return
|
|
159
|
+
return null;
|
|
163
160
|
}
|
|
164
161
|
const availableSlaves = result
|
|
165
162
|
.map(utils_1.packObject)
|
|
166
163
|
.filter((slave) => slave.flags && !slave.flags.match(/(disconnected|s_down|o_down)/));
|
|
167
|
-
|
|
164
|
+
return this.sentinelNatResolve(selectPreferredSentinel(availableSlaves, this.options.preferredSlaves));
|
|
168
165
|
});
|
|
169
166
|
}
|
|
170
167
|
sentinelNatResolve(item) {
|
|
@@ -172,30 +169,38 @@ class SentinelConnector extends AbstractConnector_1.default {
|
|
|
172
169
|
return item;
|
|
173
170
|
return this.options.natMap[`${item.host}:${item.port}`] || item;
|
|
174
171
|
}
|
|
175
|
-
resolve(endpoint
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
172
|
+
resolve(endpoint) {
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
const client = new redis_1.default({
|
|
175
|
+
port: endpoint.port || 26379,
|
|
176
|
+
host: endpoint.host,
|
|
177
|
+
username: this.options.sentinelUsername || null,
|
|
178
|
+
password: this.options.sentinelPassword || null,
|
|
179
|
+
family: endpoint.family ||
|
|
180
|
+
(StandaloneConnector_1.isIIpcConnectionOptions(this.options)
|
|
181
|
+
? undefined
|
|
182
|
+
: this.options.family),
|
|
183
|
+
tls: this.options.sentinelTLS,
|
|
184
|
+
retryStrategy: null,
|
|
185
|
+
enableReadyCheck: false,
|
|
186
|
+
connectTimeout: this.options.connectTimeout,
|
|
187
|
+
commandTimeout: this.options.sentinelCommandTimeout,
|
|
188
|
+
dropBufferSupport: true,
|
|
189
|
+
});
|
|
190
|
+
// ignore the errors since resolve* methods will handle them
|
|
191
|
+
client.on("error", noop);
|
|
192
|
+
try {
|
|
193
|
+
if (this.options.role === "slave") {
|
|
194
|
+
return yield this.resolveSlave(client);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
return yield this.resolveMaster(client);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
client.disconnect();
|
|
202
|
+
}
|
|
190
203
|
});
|
|
191
|
-
// ignore the errors since resolve* methods will handle them
|
|
192
|
-
client.on("error", noop);
|
|
193
|
-
if (this.options.role === "slave") {
|
|
194
|
-
this.resolveSlave(client, callback);
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
this.resolveMaster(client, callback);
|
|
198
|
-
}
|
|
199
204
|
}
|
|
200
205
|
}
|
|
201
206
|
exports.default = SentinelConnector;
|
|
@@ -10,7 +10,7 @@ function isIIpcConnectionOptions(value) {
|
|
|
10
10
|
exports.isIIpcConnectionOptions = isIIpcConnectionOptions;
|
|
11
11
|
class StandaloneConnector extends AbstractConnector_1.default {
|
|
12
12
|
constructor(options) {
|
|
13
|
-
super();
|
|
13
|
+
super(options.disconnectTimeout);
|
|
14
14
|
this.options = options;
|
|
15
15
|
}
|
|
16
16
|
connect(_) {
|
|
@@ -36,7 +36,11 @@ function connectHandler(self) {
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
if (self.condition.select) {
|
|
39
|
-
self.select(self.condition.select)
|
|
39
|
+
self.select(self.condition.select).catch((err) => {
|
|
40
|
+
// If the node is in cluster mode, select is disallowed.
|
|
41
|
+
// In this case, reconnect won't help.
|
|
42
|
+
self.silentEmit("error", err);
|
|
43
|
+
});
|
|
40
44
|
}
|
|
41
45
|
if (!self.options.enableReadyCheck) {
|
|
42
46
|
exports.readyHandler(self)();
|
package/built/redis/index.js
CHANGED
|
@@ -623,6 +623,13 @@ Redis.prototype.sendCommand = function (command, stream) {
|
|
|
623
623
|
command.reject(new Error("Connection in subscriber mode, only subscriber commands may be used"));
|
|
624
624
|
return command.promise;
|
|
625
625
|
}
|
|
626
|
+
if (typeof this.options.commandTimeout === "number") {
|
|
627
|
+
setTimeout(() => {
|
|
628
|
+
if (!command.isResolved) {
|
|
629
|
+
command.reject(new Error("Command timed out"));
|
|
630
|
+
}
|
|
631
|
+
}, this.options.commandTimeout);
|
|
632
|
+
}
|
|
626
633
|
if (command.name === "quit") {
|
|
627
634
|
clearInterval(this._addedScriptHashesCleanInterval);
|
|
628
635
|
this._addedScriptHashesCleanInterval = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ioredis",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.26.0",
|
|
4
4
|
"description": "A robust, performance-focused and full-featured Redis client for Node.js.",
|
|
5
5
|
"main": "built/index.js",
|
|
6
6
|
"files": [
|
|
@@ -58,17 +58,17 @@
|
|
|
58
58
|
"@types/redis-errors": "1.2.0",
|
|
59
59
|
"@types/sinon": "^9.0.0",
|
|
60
60
|
"@types/uuid": "^8.3.0",
|
|
61
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^1.13.0",
|
|
62
62
|
"@typescript-eslint/parser": "^2.26.0",
|
|
63
63
|
"bluebird": "^3.7.2",
|
|
64
64
|
"chai": "^4.2.0",
|
|
65
65
|
"chai-as-promised": "^7.1.1",
|
|
66
66
|
"cronometro": "^0.6.0",
|
|
67
67
|
"cz-conventional-changelog": "^3.1.0",
|
|
68
|
-
"eslint": "^
|
|
68
|
+
"eslint": "^5.16.0",
|
|
69
69
|
"eslint-config-prettier": "^6.10.1",
|
|
70
70
|
"husky": "^4.2.3",
|
|
71
|
-
"mocha": "^
|
|
71
|
+
"mocha": "^6.2.3",
|
|
72
72
|
"prettier": "^2.0.2",
|
|
73
73
|
"pretty-quick": "^2.0.1",
|
|
74
74
|
"server-destroy": "^1.0.1",
|