infinispan 0.13.0 → 0.14.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/Dockerfile.server +8 -0
- package/README.md +4 -10
- package/docker-compose.yml +272 -0
- package/gen-asciidoc.sh +46 -0
- package/lib/codec.js +358 -27
- package/lib/functional.js +40 -7
- package/lib/infinispan.js +503 -52
- package/lib/io.js +399 -43
- package/lib/listeners.js +50 -3
- package/lib/near-cache.js +99 -0
- package/lib/protocols.js +560 -75
- package/lib/sasl/digest.js +22 -17
- package/lib/sasl/external.js +7 -4
- package/lib/sasl/factory.js +6 -5
- package/lib/sasl/oauthbearer.js +7 -5
- package/lib/sasl/plain.js +6 -4
- package/lib/sasl/scram.js +19 -11
- package/lib/utils.js +89 -24
- package/package.json +2 -2
- package/run-docker-testsuite.sh +72 -0
- package/types/index.d.ts +192 -1
package/lib/io.js
CHANGED
|
@@ -13,24 +13,35 @@
|
|
|
13
13
|
var f = require('./functional');
|
|
14
14
|
var u = require('./utils');
|
|
15
15
|
var codec = require('./codec');
|
|
16
|
+
var protocols = require('./protocols');
|
|
16
17
|
|
|
17
18
|
module.exports = transport;
|
|
18
19
|
|
|
19
20
|
var DEFAULT_CLUSTER_NAME = '___DEFAULT-CLUSTER___';
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Formats an array of connections as a display string.
|
|
24
|
+
* @param {Array} conns - Array of connection objects.
|
|
25
|
+
* @returns {string} Bracketed comma-separated string of connections.
|
|
26
|
+
*/
|
|
21
27
|
function showArrayConnections(conns) {
|
|
22
|
-
return [
|
|
28
|
+
return ['[', _.map(conns, function(c) { return c.toString(); }).join(','), ']'].join('');
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
var Connection = function(addr, transport, listeners) {
|
|
26
32
|
var id = _.uniqueId('conn_');
|
|
27
|
-
var logger = u.logger(transport.getId()
|
|
33
|
+
var logger = u.logger(`${transport.getId() }_${ id}`);
|
|
28
34
|
var sock = new net.Socket();
|
|
29
35
|
var replayable = u.replayableBuffer();
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
/** @returns {string} Formatted address string. */
|
|
32
37
|
function show() { return u.showAddress(addr); }
|
|
33
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Creates a callback for the socket connect event.
|
|
41
|
+
* @param {Function} fulfill - Promise resolve function.
|
|
42
|
+
* @param {Object} conn - The connection object.
|
|
43
|
+
* @returns {Function} Connect event handler.
|
|
44
|
+
*/
|
|
34
45
|
function onConnect(fulfill, conn) {
|
|
35
46
|
return function() {
|
|
36
47
|
logger.debugf('Connected to %s', show());
|
|
@@ -38,6 +49,11 @@
|
|
|
38
49
|
};
|
|
39
50
|
}
|
|
40
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Creates a callback for socket error events.
|
|
54
|
+
* @param {Function} reject - Promise reject function.
|
|
55
|
+
* @returns {Function} Error event handler.
|
|
56
|
+
*/
|
|
41
57
|
function onError(reject) {
|
|
42
58
|
return function(err) {
|
|
43
59
|
logger.error('Error from %s: %s', show(), err.message);
|
|
@@ -46,6 +62,10 @@
|
|
|
46
62
|
};
|
|
47
63
|
}
|
|
48
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Handles the socket end (disconnect) event.
|
|
67
|
+
* @returns {void}
|
|
68
|
+
*/
|
|
49
69
|
function onEnd() {
|
|
50
70
|
logger.debugf('Disconnected from %s', show());
|
|
51
71
|
// TODO: Try retrying on disconnect when socket.end is invoked
|
|
@@ -56,29 +76,57 @@
|
|
|
56
76
|
// transport.retryRpcs(addr); // retry RPCs in case of disconnect
|
|
57
77
|
}
|
|
58
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Rewinds the replayable buffer when a response is incomplete.
|
|
81
|
+
* @returns {void}
|
|
82
|
+
*/
|
|
59
83
|
function rewind() {
|
|
60
|
-
logger.tracef(
|
|
84
|
+
logger.tracef('Incomplete response or event, rewind buffer and wait more data');
|
|
61
85
|
replayable.rewind();
|
|
62
86
|
}
|
|
63
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Trims the replayable buffer after a successful decode.
|
|
90
|
+
* @param {Object} header - Decoded message header.
|
|
91
|
+
* @param {Object} bytebuf - Buffer with current read offset.
|
|
92
|
+
* @returns {void}
|
|
93
|
+
*/
|
|
64
94
|
function trim(header, bytebuf) {
|
|
65
|
-
logger.tracef(
|
|
95
|
+
logger.tracef('After decoding request(msgId=%d), buffer size is %d, and offset %d',
|
|
66
96
|
header.msgId, bytebuf.buf.length, bytebuf.offset);
|
|
67
97
|
replayable.trim(bytebuf);
|
|
68
98
|
}
|
|
69
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Waits for topology installation before completing the RPC, if needed.
|
|
102
|
+
* @param {Object} rpc - The pending RPC with success/fail callbacks.
|
|
103
|
+
* @param {Object} header - Decoded response header.
|
|
104
|
+
* @param {boolean} isError - Whether the response is an error.
|
|
105
|
+
* @param {Promise|undefined} topology - Pending topology update promise.
|
|
106
|
+
* @param {Object} body - Decoded response body.
|
|
107
|
+
* @returns {void}
|
|
108
|
+
*/
|
|
70
109
|
function waitTopologyThenCompleteRpc(rpc, header, isError, topology, body) {
|
|
71
110
|
if (header.hasNewTopology) {
|
|
72
111
|
// If new topology is received, rpc needs to be
|
|
73
112
|
// completed after new topology has been installed
|
|
74
113
|
topology.then(function() {
|
|
75
114
|
completeRpc(rpc, header, isError, topology, body);
|
|
76
|
-
})
|
|
115
|
+
});
|
|
77
116
|
} else {
|
|
78
117
|
completeRpc(rpc, header, isError, topology, body);
|
|
79
118
|
}
|
|
80
119
|
}
|
|
81
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Completes an RPC by invoking its success or failure callback.
|
|
123
|
+
* @param {Object} rpc - The pending RPC with success/fail callbacks.
|
|
124
|
+
* @param {Object} header - Decoded response header.
|
|
125
|
+
* @param {boolean} isError - Whether the response is an error.
|
|
126
|
+
* @param {Promise|undefined} topology - Pending topology update promise.
|
|
127
|
+
* @param {Object} body - Decoded response body.
|
|
128
|
+
* @returns {void}
|
|
129
|
+
*/
|
|
82
130
|
function completeRpc(rpc, header, isError, topology, body) {
|
|
83
131
|
logger.tracel(function() { return [
|
|
84
132
|
'Complete %s for request(msgId=%d) with %s',
|
|
@@ -92,6 +140,11 @@
|
|
|
92
140
|
transport.removeRpc(header.msgId);
|
|
93
141
|
}
|
|
94
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Handles incoming socket data by decoding headers, topologies, events, and RPC bodies.
|
|
145
|
+
* @param {Buffer} data - Raw data received from the socket.
|
|
146
|
+
* @returns {void}
|
|
147
|
+
*/
|
|
95
148
|
function onData(data) {
|
|
96
149
|
if (!f.existy(replayable))
|
|
97
150
|
replayable = u.replayableBuffer();
|
|
@@ -141,6 +194,13 @@
|
|
|
141
194
|
replayable = null;
|
|
142
195
|
}
|
|
143
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Decodes an error response and completes the associated RPC.
|
|
199
|
+
* @param {Object} header - Decoded response header.
|
|
200
|
+
* @param {Object} bytebuf - Buffer to decode from.
|
|
201
|
+
* @param {Promise|undefined} topology - Pending topology update promise.
|
|
202
|
+
* @returns {boolean} Whether decoding can continue.
|
|
203
|
+
*/
|
|
144
204
|
function decodeError(header, bytebuf, topology) {
|
|
145
205
|
var protocol = transport.getProtocol();
|
|
146
206
|
var body = protocol.decodeError(header, bytebuf);
|
|
@@ -156,6 +216,13 @@
|
|
|
156
216
|
return canDecodeMore;
|
|
157
217
|
}
|
|
158
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Decodes a successful RPC response body and completes the associated RPC.
|
|
221
|
+
* @param {Object} header - Decoded response header.
|
|
222
|
+
* @param {Object} bytebuf - Buffer to decode from.
|
|
223
|
+
* @param {Promise|undefined} topology - Pending topology update promise.
|
|
224
|
+
* @returns {boolean} Whether decoding can continue.
|
|
225
|
+
*/
|
|
159
226
|
function decodeRpcBody(header, bytebuf, topology) {
|
|
160
227
|
var protocol = transport.getProtocol();
|
|
161
228
|
var rpc = transport.findRpc(header.msgId);
|
|
@@ -172,6 +239,12 @@
|
|
|
172
239
|
}
|
|
173
240
|
}
|
|
174
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Builds TLS socket options from SSL configuration.
|
|
244
|
+
* @param {Object} sslOpts - SSL options including certificates and protocols.
|
|
245
|
+
* @param {Function} reject - Promise reject function for validation errors.
|
|
246
|
+
* @returns {Object} TLS connection options.
|
|
247
|
+
*/
|
|
175
248
|
function sslSocketOpts(sslOpts, reject) {
|
|
176
249
|
var options = {};
|
|
177
250
|
|
|
@@ -188,6 +261,12 @@
|
|
|
188
261
|
return options;
|
|
189
262
|
}
|
|
190
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Adds client authentication options to the TLS options.
|
|
266
|
+
* @param {Object} options - Existing TLS options.
|
|
267
|
+
* @param {Object} authOpts - Client auth config with key, cert, and passphrase.
|
|
268
|
+
* @returns {Object} Updated TLS options.
|
|
269
|
+
*/
|
|
191
270
|
function sslClientAuthOpts(options, authOpts) {
|
|
192
271
|
if (f.existy(authOpts)) {
|
|
193
272
|
options.key = readFileIfExists(authOpts, 'key');
|
|
@@ -197,13 +276,20 @@
|
|
|
197
276
|
return options;
|
|
198
277
|
}
|
|
199
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Adds PKCS#12 crypto store options to the TLS options.
|
|
281
|
+
* @param {Object} options - Existing TLS options.
|
|
282
|
+
* @param {Object} storeOpts - Crypto store config with path and passphrase.
|
|
283
|
+
* @param {Function} reject - Promise reject function for validation errors.
|
|
284
|
+
* @returns {Object} Updated TLS options.
|
|
285
|
+
*/
|
|
200
286
|
function sslCryptoStoreOpts(options, storeOpts, reject) {
|
|
201
287
|
if (f.existy(storeOpts)) {
|
|
202
288
|
if (!f.existy(storeOpts.path))
|
|
203
|
-
reject(new Error('No path defined for crypto store'));
|
|
289
|
+
return reject(new Error('No path defined for crypto store'));
|
|
204
290
|
|
|
205
291
|
if (!f.existy(storeOpts.passphrase))
|
|
206
|
-
reject(new Error('No passphrase defined for crypto store'));
|
|
292
|
+
return reject(new Error('No passphrase defined for crypto store'));
|
|
207
293
|
|
|
208
294
|
options.pfx = fs.readFileSync(storeOpts.path);
|
|
209
295
|
options.passphrase = storeOpts.passphrase;
|
|
@@ -211,16 +297,35 @@
|
|
|
211
297
|
return options;
|
|
212
298
|
}
|
|
213
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Reads a file specified by a property on the parent object, if defined.
|
|
302
|
+
* @param {Object} parent - Object containing the file path property.
|
|
303
|
+
* @param {string} opt - Property name whose value is the file path.
|
|
304
|
+
* @returns {Buffer|undefined} File contents or undefined.
|
|
305
|
+
*/
|
|
214
306
|
function readFileIfExists(parent, opt) {
|
|
215
307
|
return f.existy(parent[opt])
|
|
216
308
|
? fs.readFileSync(parent[opt])
|
|
217
309
|
: undefined;
|
|
218
310
|
}
|
|
219
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Connects via a plain (non-TLS) TCP socket.
|
|
314
|
+
* @param {Function} fulfill - Promise resolve function.
|
|
315
|
+
* @param {Object} conn - The connection object.
|
|
316
|
+
* @returns {Object} The socket instance.
|
|
317
|
+
*/
|
|
220
318
|
function connectPlainSocket(fulfill, conn) {
|
|
221
319
|
return sock.connect(addr.port, addr.host, onConnect(fulfill, conn));
|
|
222
320
|
}
|
|
223
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Connects via a TLS-encrypted socket.
|
|
324
|
+
* @param {Function} fulfill - Promise resolve function.
|
|
325
|
+
* @param {Function} reject - Promise reject function.
|
|
326
|
+
* @param {Object} conn - The connection object.
|
|
327
|
+
* @returns {Object} The TLS socket instance.
|
|
328
|
+
*/
|
|
224
329
|
function connectSslSocket(fulfill, reject, conn) {
|
|
225
330
|
var sslOpts = transport.sslOpts();
|
|
226
331
|
var options = sslSocketOpts(sslOpts, reject);
|
|
@@ -257,7 +362,7 @@
|
|
|
257
362
|
},
|
|
258
363
|
write: function(buffer) {
|
|
259
364
|
return new Promise(function (fulfill, reject) {
|
|
260
|
-
var flushed = sock.write(buffer,
|
|
365
|
+
var flushed = sock.write(buffer, err => {
|
|
261
366
|
if (err) {
|
|
262
367
|
logger.error('Error writing to socket: %s', err);
|
|
263
368
|
transport.retryRpcs(addr); // retry RPCs in case of error
|
|
@@ -274,7 +379,7 @@
|
|
|
274
379
|
return addr;
|
|
275
380
|
},
|
|
276
381
|
toString: function() {
|
|
277
|
-
return show()
|
|
382
|
+
return `${show() }@${ id}`;
|
|
278
383
|
}
|
|
279
384
|
};
|
|
280
385
|
return conn;
|
|
@@ -284,6 +389,11 @@
|
|
|
284
389
|
var i = 0;
|
|
285
390
|
var mh3 = u.murmurHash3();
|
|
286
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Finds connections not present in the given address list.
|
|
394
|
+
* @param {Array} addrs - Array of server addresses to check against.
|
|
395
|
+
* @returns {Array} Connections missing from the address list.
|
|
396
|
+
*/
|
|
287
397
|
function filterNot(addrs) {
|
|
288
398
|
var missing = _.filter(conns, function(c) {
|
|
289
399
|
return !_.where(addrs, c.getAddress()).length > 0;
|
|
@@ -293,34 +403,64 @@
|
|
|
293
403
|
return missing;
|
|
294
404
|
}
|
|
295
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Returns the next connection using round-robin selection.
|
|
408
|
+
* @returns {Object} The next connection in rotation.
|
|
409
|
+
*/
|
|
296
410
|
function getConnectionRoundRobin() {
|
|
297
411
|
var conn = conns[i++];
|
|
298
412
|
if (i >= conns.length) i = 0;
|
|
299
413
|
return conn;
|
|
300
414
|
}
|
|
301
415
|
|
|
416
|
+
/**
|
|
417
|
+
* Finds a connection whose address has not been tried yet.
|
|
418
|
+
* @param {Array} triedAddrs - Array of already-tried addresses.
|
|
419
|
+
* @returns {Object|undefined} An untried connection, or undefined.
|
|
420
|
+
*/
|
|
302
421
|
function findConnectionUntried(triedAddrs) {
|
|
303
422
|
return _.find(conns, function(c) {
|
|
304
423
|
return !_.contains(triedAddrs, c.getAddress());
|
|
305
424
|
});
|
|
306
425
|
}
|
|
307
426
|
|
|
427
|
+
/**
|
|
428
|
+
* Computes the size of each hash segment.
|
|
429
|
+
* @param {number} numSegments - Total number of segments.
|
|
430
|
+
* @returns {number} The size of each segment.
|
|
431
|
+
*/
|
|
308
432
|
function getSegmentSize(numSegments) {
|
|
309
433
|
return Math.abs(Math.ceil((1 << 31) / numSegments));
|
|
310
434
|
}
|
|
311
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Computes a non-negative MurmurHash3 hash for the given buffer.
|
|
438
|
+
* @param {Buffer} buf - The buffer to hash.
|
|
439
|
+
* @returns {number} Non-negative 32-bit hash value.
|
|
440
|
+
*/
|
|
312
441
|
function getNormalizedHash(buf) {
|
|
313
442
|
// make sure no negative numbers are involved.
|
|
314
443
|
var hash = mh3.hash(buf);
|
|
315
444
|
return hash & 0x7FFFFFFF;
|
|
316
445
|
}
|
|
317
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Encodes a key to its byte representation using the protocol codec.
|
|
449
|
+
* @param {string|Object} k - The cache key to encode.
|
|
450
|
+
* @param {Object} protocol - The Hot Rod protocol instance.
|
|
451
|
+
* @returns {Buffer} Encoded key bytes.
|
|
452
|
+
*/
|
|
318
453
|
function keyToBytes(k, protocol) {
|
|
319
454
|
var ctx = u.context(32);
|
|
320
455
|
f.actions([protocol.encodeMediaKey(k)], codec.bytesEncoded)(ctx);
|
|
321
456
|
return f.actions([codec.decodeVariableBytes()], codec.lastDecoded)({buf: ctx.buf, offset: 0});
|
|
322
457
|
}
|
|
323
458
|
|
|
459
|
+
/**
|
|
460
|
+
* Finds the connection matching the given address.
|
|
461
|
+
* @param {Object} addr - Server address with host and port.
|
|
462
|
+
* @returns {Object|undefined} The matching connection, or undefined.
|
|
463
|
+
*/
|
|
324
464
|
function addrToConn(addr) {
|
|
325
465
|
return _.find(conns, function(con) {
|
|
326
466
|
return _.isEqual(con.getAddress(), addr);
|
|
@@ -365,10 +505,15 @@
|
|
|
365
505
|
toString: function() {
|
|
366
506
|
return util.format('ConsistentHashRouter(conns=%s)', showArrayConnections(conns));
|
|
367
507
|
}
|
|
368
|
-
}
|
|
508
|
+
};
|
|
369
509
|
};
|
|
370
510
|
|
|
371
511
|
var FixedRouter = function(logger, conn, clusterName) {
|
|
512
|
+
/**
|
|
513
|
+
* Checks whether this connection's address is absent from the given list.
|
|
514
|
+
* @param {Array} addrs - Array of server addresses.
|
|
515
|
+
* @returns {boolean} True if this connection's address is not in the list.
|
|
516
|
+
*/
|
|
372
517
|
function isMemberMissing(addrs) {
|
|
373
518
|
return _.isEmpty(_.find(addrs, function(addr) {
|
|
374
519
|
return _.isMatch(addr, conn.getAddress());
|
|
@@ -400,7 +545,7 @@
|
|
|
400
545
|
var isMissing = !_.isEmpty(missing);
|
|
401
546
|
if (isMissing) {
|
|
402
547
|
logger.debugf('Removed server is: %s', conn.toString());
|
|
403
|
-
return conn.disconnect()
|
|
548
|
+
return conn.disconnect();
|
|
404
549
|
} else {
|
|
405
550
|
logger.debugf('Removed server: none');
|
|
406
551
|
return Promise.resolve();
|
|
@@ -415,9 +560,17 @@
|
|
|
415
560
|
toString: function() {
|
|
416
561
|
return util.format('FixedRouter(conn=%s)', conn.toString());
|
|
417
562
|
}
|
|
418
|
-
}
|
|
563
|
+
};
|
|
419
564
|
};
|
|
420
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Creates a transport layer managing connections, routing, and failover.
|
|
568
|
+
* @param {Array} addrs - Initial server addresses to connect to.
|
|
569
|
+
* @param {Object} protocol - The Hot Rod protocol instance.
|
|
570
|
+
* @param {Object} clientOpts - Client configuration options.
|
|
571
|
+
* @param {Object} listeners - Event listener manager.
|
|
572
|
+
* @returns {Object} Transport object with connect, write, and topology methods.
|
|
573
|
+
*/
|
|
421
574
|
function transport(addrs, protocol, clientOpts, listeners) {
|
|
422
575
|
var id = _.uniqueId('io_');
|
|
423
576
|
var logger = u.logger(id);
|
|
@@ -428,6 +581,11 @@
|
|
|
428
581
|
[{ name: DEFAULT_CLUSTER_NAME, servers: addrs}]);
|
|
429
582
|
var clusterSwitchInProgress = false;
|
|
430
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Installs a new router and retries all RPCs if a cluster switch occurred.
|
|
586
|
+
* @param {Object} r - The new router to install.
|
|
587
|
+
* @returns {void}
|
|
588
|
+
*/
|
|
431
589
|
function onRouter(r) {
|
|
432
590
|
// Check if a different router has been installed as result of cluster switch
|
|
433
591
|
var isRetryAll = f.existy(router)
|
|
@@ -435,10 +593,10 @@
|
|
|
435
593
|
|
|
436
594
|
// var oldRouter = router;
|
|
437
595
|
router = r; // Assign new router
|
|
438
|
-
logger.debugf(
|
|
596
|
+
logger.debugf('New router installed: %s', r.toString());
|
|
439
597
|
|
|
440
598
|
if (isRetryAll) {
|
|
441
|
-
logger.debugf(
|
|
599
|
+
logger.debugf('Retry all after new router installed %s', r.toString());
|
|
442
600
|
retryAll(); // If cluster switched happened, retry all rpcs
|
|
443
601
|
clusterSwitchInProgress = false;
|
|
444
602
|
}
|
|
@@ -450,6 +608,10 @@
|
|
|
450
608
|
// }
|
|
451
609
|
}
|
|
452
610
|
|
|
611
|
+
/**
|
|
612
|
+
* Retries all pending RPCs after a cluster switch.
|
|
613
|
+
* @returns {void}
|
|
614
|
+
*/
|
|
453
615
|
function retryAll() {
|
|
454
616
|
_.each(rpcMap.values(), function(rpc) {
|
|
455
617
|
rpc.ctx.triedAddrs = [];
|
|
@@ -461,6 +623,11 @@
|
|
|
461
623
|
});
|
|
462
624
|
}
|
|
463
625
|
|
|
626
|
+
/**
|
|
627
|
+
* Filters topology servers to find newly added addresses.
|
|
628
|
+
* @param {Object} topology - The new topology with server addresses.
|
|
629
|
+
* @returns {Array} Server addresses not present in the current router.
|
|
630
|
+
*/
|
|
464
631
|
function filterAdded(topology) {
|
|
465
632
|
var currentAddrs = router.getAddresses();
|
|
466
633
|
var added = _.filter(topology.servers, function(a) {
|
|
@@ -471,6 +638,11 @@
|
|
|
471
638
|
return added;
|
|
472
639
|
}
|
|
473
640
|
|
|
641
|
+
/**
|
|
642
|
+
* Filters current router addresses to find those still present in the new topology.
|
|
643
|
+
* @param {Object} topology - The new topology with server addresses.
|
|
644
|
+
* @returns {Array} Addresses that remain connected in the new topology.
|
|
645
|
+
*/
|
|
474
646
|
function filterConnected(topology) {
|
|
475
647
|
var connected = _.filter(router.getAddresses(), function(addr) {
|
|
476
648
|
return _.where(topology.servers, addr).length > 0;
|
|
@@ -480,6 +652,14 @@
|
|
|
480
652
|
return connected;
|
|
481
653
|
}
|
|
482
654
|
|
|
655
|
+
/**
|
|
656
|
+
* Writes an encoded command to a connection and registers the RPC for response.
|
|
657
|
+
* @param {Object} ctx - Encoding context with buffer and message ID.
|
|
658
|
+
* @param {Function} decoder - Response decoder function.
|
|
659
|
+
* @param {Function} connFunc - Function returning the target connection.
|
|
660
|
+
* @param {Function} [preWrite] - Optional callback invoked before writing.
|
|
661
|
+
* @returns {Promise} Resolves with the decoded response.
|
|
662
|
+
*/
|
|
483
663
|
function write(ctx, decoder, connFunc, preWrite) {
|
|
484
664
|
return new Promise(function (fulfill, reject) {
|
|
485
665
|
var conn = connFunc();
|
|
@@ -496,6 +676,15 @@
|
|
|
496
676
|
});
|
|
497
677
|
}
|
|
498
678
|
|
|
679
|
+
/**
|
|
680
|
+
* Writes a retried RPC command to a specific connection.
|
|
681
|
+
* @param {Object} ctx - Encoding context with buffer and message ID.
|
|
682
|
+
* @param {Function} decoder - Response decoder function.
|
|
683
|
+
* @param {Object} conn - The target connection.
|
|
684
|
+
* @param {Function} fulfill - Promise resolve function.
|
|
685
|
+
* @param {Function} reject - Promise reject function.
|
|
686
|
+
* @returns {void}
|
|
687
|
+
*/
|
|
499
688
|
function writeRetry(ctx, decoder, conn, fulfill, reject) {
|
|
500
689
|
logger.tracel(function() {
|
|
501
690
|
return ['Write retried buffer(msgId=%d) to %s: %s'
|
|
@@ -506,23 +695,35 @@
|
|
|
506
695
|
conn.write(ctx.buf);
|
|
507
696
|
}
|
|
508
697
|
|
|
698
|
+
/**
|
|
699
|
+
* Disconnects the existing router and installs a new one.
|
|
700
|
+
* @param {Object} newRouter - The new router to install.
|
|
701
|
+
* @returns {Promise} Resolves when the new router is installed.
|
|
702
|
+
*/
|
|
509
703
|
function disconnectAndEmitRouter(newRouter) {
|
|
510
704
|
if (f.existy(router)) {
|
|
511
705
|
// Disconnect existing router connections
|
|
512
706
|
// and regardless of outcome, install new router
|
|
513
|
-
router.disconnect().finally(function() {
|
|
707
|
+
return router.disconnect().finally(function() {
|
|
514
708
|
onRouter(newRouter);
|
|
515
|
-
})
|
|
709
|
+
});
|
|
516
710
|
} else {
|
|
517
711
|
onRouter(newRouter);
|
|
712
|
+
return Promise.resolve();
|
|
518
713
|
}
|
|
519
714
|
}
|
|
520
715
|
|
|
716
|
+
/**
|
|
717
|
+
* Installs a new topology by updating connections and router.
|
|
718
|
+
* @param {Object} topology - New topology with server addresses and segments.
|
|
719
|
+
* @param {Object} transport - The transport instance.
|
|
720
|
+
* @returns {Promise} Resolves when the new topology is fully installed.
|
|
721
|
+
*/
|
|
521
722
|
function installNewTopology(topology, transport) {
|
|
522
723
|
var newAddrs = topology.servers;
|
|
523
724
|
logger.debugl(function() {return [
|
|
524
725
|
'New topology(id=%s) discovered: %s',
|
|
525
|
-
topology.id, u.showArrayAddress(newAddrs)] });
|
|
726
|
+
topology.id, u.showArrayAddress(newAddrs)]; });
|
|
526
727
|
|
|
527
728
|
// Disconnect connections for members not present in topology
|
|
528
729
|
var missing = router.getMissingConnections(topology);
|
|
@@ -551,7 +752,7 @@
|
|
|
551
752
|
return conn.connect().then(function() {
|
|
552
753
|
if(transport.authOpts().enabled) {
|
|
553
754
|
return authMech(transport, conn, topology.id)
|
|
554
|
-
.then(function (
|
|
755
|
+
.then(function (_) {
|
|
555
756
|
return auth(transport, conn, topology.id).then(function () {
|
|
556
757
|
return conn;
|
|
557
758
|
});
|
|
@@ -561,30 +762,43 @@
|
|
|
561
762
|
return conn;
|
|
562
763
|
});
|
|
563
764
|
}
|
|
564
|
-
})
|
|
765
|
+
});
|
|
565
766
|
}));
|
|
566
767
|
})
|
|
567
768
|
.then(failoverListeners(transport, missing));
|
|
568
769
|
}
|
|
569
770
|
|
|
771
|
+
/**
|
|
772
|
+
* Creates a function that fails over listeners from removed connections.
|
|
773
|
+
* @param {Object} transport - The transport instance.
|
|
774
|
+
* @param {Array} missing - Connections that were removed from the topology.
|
|
775
|
+
* @returns {Function} Failover function that re-registers listeners.
|
|
776
|
+
*/
|
|
570
777
|
function failoverListeners(transport, missing) {
|
|
571
778
|
return function() {
|
|
572
|
-
logger.debugf(
|
|
779
|
+
logger.debugf('Failover listeners registered in: %s', showArrayConnections(missing));
|
|
573
780
|
|
|
574
781
|
var failover = _.map(missing, function(c) {
|
|
575
782
|
var listenersAt = listeners.getListenersAt(c.getAddress());
|
|
576
783
|
|
|
577
784
|
return _.map(listenersAt, function(listener) {
|
|
578
|
-
logger.debugf(
|
|
785
|
+
logger.debugf('Failover listener with id: %s', listener.id);
|
|
579
786
|
listeners.removeListeners(listener.id);
|
|
580
787
|
return listeners.addRemoteListener(transport, transport.context(32), listener.event, listener.callback);
|
|
581
788
|
});
|
|
582
789
|
});
|
|
583
790
|
|
|
584
791
|
return Promise.all(_.flatten(failover));
|
|
585
|
-
}
|
|
792
|
+
};
|
|
586
793
|
}
|
|
587
794
|
|
|
795
|
+
/**
|
|
796
|
+
* Creates lazy connection factories that install a FixedRouter on first call.
|
|
797
|
+
* @param {Array} servers - Server addresses to create connections for.
|
|
798
|
+
* @param {Function} connF - Connection callback to invoke after connecting.
|
|
799
|
+
* @param {Object} transport - The transport instance.
|
|
800
|
+
* @returns {Array} Array of lazy connection factory functions.
|
|
801
|
+
*/
|
|
588
802
|
function toLazyConnectionsFirstCall(servers, connF, transport) {
|
|
589
803
|
return _.map(servers, function(server) {
|
|
590
804
|
return function() {
|
|
@@ -595,6 +809,13 @@
|
|
|
595
809
|
});
|
|
596
810
|
}
|
|
597
811
|
|
|
812
|
+
/**
|
|
813
|
+
* Creates lazy connection factories for the given servers.
|
|
814
|
+
* @param {Array} servers - Server addresses to create connections for.
|
|
815
|
+
* @param {Function} connF - Connection callback to invoke after connecting.
|
|
816
|
+
* @param {Object} transport - The transport instance.
|
|
817
|
+
* @returns {Array} Array of lazy connection factory functions.
|
|
818
|
+
*/
|
|
598
819
|
function toLazyConnections(servers, connF, transport) {
|
|
599
820
|
return _.map(servers, function(server) {
|
|
600
821
|
return function() {
|
|
@@ -604,21 +825,36 @@
|
|
|
604
825
|
});
|
|
605
826
|
}
|
|
606
827
|
|
|
828
|
+
/**
|
|
829
|
+
* Returns clusters excluding the one that failed.
|
|
830
|
+
* @param {string} failedClusterName - Name of the failed cluster.
|
|
831
|
+
* @returns {Array} Alternative cluster configurations.
|
|
832
|
+
*/
|
|
607
833
|
function getCandidateClusters(failedClusterName) {
|
|
608
834
|
return _.filter(clusters, function(cluster) {
|
|
609
835
|
return !_.isEqual(cluster.name, failedClusterName);
|
|
610
836
|
});
|
|
611
837
|
}
|
|
612
838
|
|
|
839
|
+
/**
|
|
840
|
+
* Creates a callback that installs a new router after failover.
|
|
841
|
+
* @param {string} failedClusterName - Name of the cluster that failed.
|
|
842
|
+
* @returns {Function} Callback accepting connection info to install new router.
|
|
843
|
+
*/
|
|
613
844
|
function getFailoverMainRouter(failedClusterName) {
|
|
614
845
|
return function(connInfo) {
|
|
615
846
|
logger.debugf('Switched from failed cluster=%s to cluster=%s',
|
|
616
847
|
failedClusterName, connInfo[0]);
|
|
617
|
-
disconnectAndEmitRouter(new FixedRouter(logger, connInfo[1], connInfo[0]))
|
|
618
|
-
|
|
619
|
-
}
|
|
848
|
+
return disconnectAndEmitRouter(new FixedRouter(logger, connInfo[1], connInfo[0]))
|
|
849
|
+
.then(function() { return true; });
|
|
850
|
+
};
|
|
620
851
|
}
|
|
621
852
|
|
|
853
|
+
/**
|
|
854
|
+
* Creates a connection factory for an alternative cluster.
|
|
855
|
+
* @param {string} clusterName - Name of the alternative cluster.
|
|
856
|
+
* @returns {Function} Factory that connects and optionally authenticates.
|
|
857
|
+
*/
|
|
622
858
|
function altConnection(clusterName) {
|
|
623
859
|
return function(conn) {
|
|
624
860
|
logger.debugf('Alt connection %s', clusterName);
|
|
@@ -632,14 +868,26 @@
|
|
|
632
868
|
}
|
|
633
869
|
return conn;
|
|
634
870
|
})]);
|
|
635
|
-
}
|
|
871
|
+
};
|
|
636
872
|
}
|
|
637
873
|
|
|
874
|
+
/**
|
|
875
|
+
* Creates lazy connection factories for an alternative cluster.
|
|
876
|
+
* @param {Object} cluster - Cluster config with name and servers.
|
|
877
|
+
* @param {Object} transport - The transport instance.
|
|
878
|
+
* @returns {Array} Array of lazy connection factory functions.
|
|
879
|
+
*/
|
|
638
880
|
function toLazyAltConnections(cluster, transport) {
|
|
639
881
|
return toLazyConnections(
|
|
640
882
|
cluster.servers, altConnection(cluster.name), transport);
|
|
641
883
|
}
|
|
642
884
|
|
|
885
|
+
/**
|
|
886
|
+
* Wraps a cluster switch operation with progress tracking.
|
|
887
|
+
* @param {Function} clusterSwitchF - Function performing the cluster switch.
|
|
888
|
+
* @param {Function} [clusterFailF] - Optional error handler if switch fails.
|
|
889
|
+
* @returns {Promise} Resolves when the cluster switch completes.
|
|
890
|
+
*/
|
|
643
891
|
function aroundClusterSwitch(clusterSwitchF, clusterFailF) {
|
|
644
892
|
logger.debugf('aroundClusterSwitch set clusterSwitchInProgress=true');
|
|
645
893
|
clusterSwitchInProgress = true;
|
|
@@ -653,6 +901,13 @@
|
|
|
653
901
|
});
|
|
654
902
|
}
|
|
655
903
|
|
|
904
|
+
/**
|
|
905
|
+
* Attempts automatic failover to an alternative cluster.
|
|
906
|
+
* @param {Function} noClustersF - Callback if no alternative clusters exist.
|
|
907
|
+
* @param {Function} clusterFailF - Callback if cluster switch fails.
|
|
908
|
+
* @param {Object} transport - The transport instance.
|
|
909
|
+
* @returns {Promise} Resolves when failover completes or is rejected.
|
|
910
|
+
*/
|
|
656
911
|
function trySwitchCluster(noClustersF, clusterFailF, transport) {
|
|
657
912
|
var failedClusterName = router.getClusterName();
|
|
658
913
|
logger.debugf('Try to failover away from cluster=%s', failedClusterName);
|
|
@@ -672,15 +927,25 @@
|
|
|
672
927
|
}
|
|
673
928
|
}
|
|
674
929
|
|
|
930
|
+
/**
|
|
931
|
+
* Installs a FixedRouter for a manually selected cluster connection.
|
|
932
|
+
* @param {Array} connInfo - Tuple of [clusterName, connection].
|
|
933
|
+
* @returns {boolean} True indicating the switch succeeded.
|
|
934
|
+
*/
|
|
675
935
|
function getManualMainRouter(connInfo) {
|
|
676
936
|
var clusterName = connInfo[0];
|
|
677
937
|
var conn = connInfo[1];
|
|
678
938
|
logger.debugf('Manually switched to cluster=%s, establishing connection to %s',
|
|
679
939
|
clusterName, conn.toString());
|
|
680
|
-
disconnectAndEmitRouter(new FixedRouter(logger, conn, clusterName))
|
|
681
|
-
|
|
940
|
+
return disconnectAndEmitRouter(new FixedRouter(logger, conn, clusterName))
|
|
941
|
+
.then(function() { return true; });
|
|
682
942
|
}
|
|
683
943
|
|
|
944
|
+
/**
|
|
945
|
+
* Finds a cluster configuration by name for manual switching.
|
|
946
|
+
* @param {string} clusterName - Target cluster name, or undefined for default.
|
|
947
|
+
* @returns {Object|undefined} The matching cluster configuration, or undefined.
|
|
948
|
+
*/
|
|
684
949
|
function findManualSwitchCluster(clusterName) {
|
|
685
950
|
var name = f.existy(clusterName) ? clusterName : DEFAULT_CLUSTER_NAME;
|
|
686
951
|
return _.find(clusters, function(cluster) {
|
|
@@ -688,6 +953,12 @@
|
|
|
688
953
|
});
|
|
689
954
|
}
|
|
690
955
|
|
|
956
|
+
/**
|
|
957
|
+
* Attempts a manual switch to a named cluster.
|
|
958
|
+
* @param {string} clusterName - Name of the target cluster.
|
|
959
|
+
* @param {Object} transport - The transport instance.
|
|
960
|
+
* @returns {Promise<boolean>} Resolves true if switch succeeded, false otherwise.
|
|
961
|
+
*/
|
|
691
962
|
function tryManualSwitchCluster(clusterName, transport) {
|
|
692
963
|
logger.debugf('Try to manually switch to cluster=%s', clusterName);
|
|
693
964
|
var targetCluster = findManualSwitchCluster(clusterName);
|
|
@@ -702,35 +973,59 @@
|
|
|
702
973
|
}, function () {
|
|
703
974
|
logger.error('Unable to switch to cluster %s', targetCluster.name);
|
|
704
975
|
return Promise.resolve(false);
|
|
705
|
-
})
|
|
976
|
+
});
|
|
706
977
|
}
|
|
707
978
|
|
|
979
|
+
/**
|
|
980
|
+
* Establishes and authenticates the main connection to a server.
|
|
981
|
+
* @param {Object} conn - The connection to establish.
|
|
982
|
+
* @returns {Promise<Object>} Resolves with the connected connection.
|
|
983
|
+
*/
|
|
708
984
|
function mainConnection(conn) {
|
|
985
|
+
var connPromise = conn.connect();
|
|
986
|
+
|
|
987
|
+
if (clientOpts.version === 'auto') {
|
|
988
|
+
connPromise = connPromise.then(function() {
|
|
989
|
+
return negotiateProtocol(o, conn, o.getTopologyId(), clientOpts);
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
|
|
709
993
|
if (o.authOpts().enabled) {
|
|
710
|
-
return
|
|
994
|
+
return connPromise.then(function () {
|
|
711
995
|
return authMech(o, conn, o.getTopologyId());
|
|
712
996
|
}).then(function (authMechs) {
|
|
713
997
|
logger.tracef(authMechs);
|
|
714
998
|
if (!_.contains(authMechs, o.authOpts().saslMechanism)) {
|
|
715
|
-
throw new Error(
|
|
716
|
-
|
|
999
|
+
throw new Error(`The selected authentication mechanism ${ o.authOpts().saslMechanism
|
|
1000
|
+
} is not among the supported server mechanisms: ${ authMechs}`);
|
|
717
1001
|
}
|
|
718
1002
|
return auth(o, conn, o.getTopologyId());
|
|
719
1003
|
}).then(conn);
|
|
720
1004
|
}
|
|
721
1005
|
|
|
722
|
-
return
|
|
1006
|
+
return connPromise.then(function () {
|
|
723
1007
|
return ping(o, conn, o.getTopologyId());
|
|
724
1008
|
}).then(conn);
|
|
725
1009
|
}
|
|
726
1010
|
|
|
1011
|
+
/**
|
|
1012
|
+
* Tries lazy connections in order, returning the first successful one.
|
|
1013
|
+
* @param {Array<Function>} lazyConns - Array of lazy connection factory functions.
|
|
1014
|
+
* @returns {Promise<Object>} Resolves with the first successful connection.
|
|
1015
|
+
*/
|
|
727
1016
|
function getFirstConnection(lazyConns) {
|
|
728
1017
|
return _.foldl(lazyConns, function(state, f) {
|
|
729
1018
|
return state
|
|
730
|
-
.catch(function() { return f(); } ) // if fails, try next
|
|
1019
|
+
.catch(function() { return f(); } ); // if fails, try next
|
|
731
1020
|
}, Promise.reject(new Error('Unable to find the first connection')));
|
|
732
1021
|
}
|
|
733
1022
|
|
|
1023
|
+
/**
|
|
1024
|
+
* Tries lazy connections in order and applies a callback to the first success.
|
|
1025
|
+
* @param {Array<Function>} lazyConns - Array of lazy connection factory functions.
|
|
1026
|
+
* @param {Function} connF - Callback applied to the successful connection.
|
|
1027
|
+
* @returns {Promise} Resolves with the callback result.
|
|
1028
|
+
*/
|
|
734
1029
|
function findFirstConnection(lazyConns, connF) {
|
|
735
1030
|
logger.debugf('Call findFirstConnection');
|
|
736
1031
|
|
|
@@ -741,10 +1036,13 @@
|
|
|
741
1036
|
}, Promise.reject(new Error('Unable to find a connection')));
|
|
742
1037
|
}
|
|
743
1038
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1039
|
+
/**
|
|
1040
|
+
* Sends a ping request to a server connection.
|
|
1041
|
+
* @param {Object} transport - The transport instance.
|
|
1042
|
+
* @param {Object} conn - The connection to ping.
|
|
1043
|
+
* @param {number} topologyId - Current topology ID.
|
|
1044
|
+
* @returns {Promise} Resolves with the ping response.
|
|
1045
|
+
*/
|
|
748
1046
|
function ping(transport, conn, topologyId) {
|
|
749
1047
|
var ctx = u.context(16);
|
|
750
1048
|
ctx.topologyId = topologyId;
|
|
@@ -754,6 +1052,56 @@
|
|
|
754
1052
|
return transport.writeCommandPinned(ctx, p.decodePingResponse, conn);
|
|
755
1053
|
}
|
|
756
1054
|
|
|
1055
|
+
/**
|
|
1056
|
+
* Negotiates the highest protocol version supported by the server.
|
|
1057
|
+
* Tries versions in descending order, starting from the highest.
|
|
1058
|
+
* @param {Object} transport - The transport instance.
|
|
1059
|
+
* @param {Object} conn - The connection to negotiate on.
|
|
1060
|
+
* @param {number} topologyId - Current topology ID.
|
|
1061
|
+
* @param {Object} cOpts - Client configuration options.
|
|
1062
|
+
* @returns {Promise<string>} Resolves with the negotiated version string.
|
|
1063
|
+
*/
|
|
1064
|
+
function negotiateProtocol(transport, conn, topologyId, cOpts) {
|
|
1065
|
+
var versions = protocols.VERSION_ORDER;
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* @param {number} index Version index to try.
|
|
1069
|
+
* @returns {Promise<string>} Resolves with negotiated version.
|
|
1070
|
+
*/
|
|
1071
|
+
function tryVersion(index) {
|
|
1072
|
+
if (index >= versions.length)
|
|
1073
|
+
return Promise.reject(new Error('No compatible protocol version found'));
|
|
1074
|
+
|
|
1075
|
+
var version = versions[index];
|
|
1076
|
+
var candidateProtocol = protocols.resolve(version, cOpts);
|
|
1077
|
+
|
|
1078
|
+
transport.setProtocol(candidateProtocol);
|
|
1079
|
+
|
|
1080
|
+
return ping(transport, conn, topologyId)
|
|
1081
|
+
.then(function() {
|
|
1082
|
+
logger.debugf('Protocol negotiation succeeded with version %s', version);
|
|
1083
|
+
return version;
|
|
1084
|
+
})
|
|
1085
|
+
.catch(function(err) {
|
|
1086
|
+
var msg = typeof err === 'string' ? err : (err && err.message) || '';
|
|
1087
|
+
if (msg.indexOf('CacheNotFoundException') >= 0) {
|
|
1088
|
+
return Promise.reject(err);
|
|
1089
|
+
}
|
|
1090
|
+
logger.debugf('Protocol version %s not supported, trying next', version);
|
|
1091
|
+
return tryVersion(index + 1);
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
return tryVersion(0);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Performs SASL authentication on a connection.
|
|
1100
|
+
* @param {Object} transport - The transport instance.
|
|
1101
|
+
* @param {Object} conn - The connection to authenticate.
|
|
1102
|
+
* @param {number} topologyId - Current topology ID.
|
|
1103
|
+
* @returns {Promise<Object>} Resolves with the authenticated connection.
|
|
1104
|
+
*/
|
|
757
1105
|
function auth(transport, conn, topologyId) {
|
|
758
1106
|
if (!transport.authOpts().enabled || conn.authDone) {
|
|
759
1107
|
logger.debugf('Auth not enabled');
|
|
@@ -779,6 +1127,13 @@
|
|
|
779
1127
|
});
|
|
780
1128
|
}
|
|
781
1129
|
|
|
1130
|
+
/**
|
|
1131
|
+
* Queries the server for supported authentication mechanisms.
|
|
1132
|
+
* @param {Object} transport - The transport instance.
|
|
1133
|
+
* @param {Object} conn - The connection to query.
|
|
1134
|
+
* @param {number} topologyId - Current topology ID.
|
|
1135
|
+
* @returns {Promise<Array>} Resolves with the list of supported SASL mechanisms.
|
|
1136
|
+
*/
|
|
782
1137
|
function authMech(transport, conn, topologyId) {
|
|
783
1138
|
if (!transport.authOpts().enabled) {
|
|
784
1139
|
logger.debugf('Auth not enabled');
|
|
@@ -830,7 +1185,7 @@
|
|
|
830
1185
|
writeRetry(ctx, decoder, conn, fulfill, reject);
|
|
831
1186
|
else {
|
|
832
1187
|
trySwitchCluster(
|
|
833
|
-
function() { reject('No clusters and no connections left to try on writeRetry.') },
|
|
1188
|
+
function() { reject('No clusters and no connections left to try on writeRetry.'); },
|
|
834
1189
|
function(err) {
|
|
835
1190
|
logger.tracef('Clusters configured but none available on writeRetry: %s', err.message);
|
|
836
1191
|
reject('Clusters configured but none available on writeRetry. No connections left to try');
|
|
@@ -838,6 +1193,7 @@
|
|
|
838
1193
|
}
|
|
839
1194
|
},
|
|
840
1195
|
getProtocol: function() { return protocol; },
|
|
1196
|
+
setProtocol: function(newProtocol) { protocol = newProtocol; },
|
|
841
1197
|
findRpc: function(id) { return rpcMap.get(id); },
|
|
842
1198
|
removeRpc: function(id) { return rpcMap.remove(id); },
|
|
843
1199
|
updateTopology: function(bytebuf) {
|
|
@@ -862,7 +1218,7 @@
|
|
|
862
1218
|
function(rpc) { return _.isEqual(rpc.address, addr); });
|
|
863
1219
|
|
|
864
1220
|
logger.tracel(function() {
|
|
865
|
-
return ['Pending request ids are: [%s]', _.keys(pendingRpcs)] });
|
|
1221
|
+
return ['Pending request ids are: [%s]', _.keys(pendingRpcs)]; });
|
|
866
1222
|
|
|
867
1223
|
_.each(pendingRpcs, function(rpc, id) {
|
|
868
1224
|
if (rpc.ctx.triedAddrs.length >= clientOpts.maxRetries) {
|
|
@@ -884,7 +1240,7 @@
|
|
|
884
1240
|
logger.tracef('Retrying request(msgId=%d), retry %d', id, rpc.ctx.triedAddrs.length);
|
|
885
1241
|
o.writeRetry(rpc.ctx, rpc.decoder, rpc.success, rpc.fail, rpc.ctx.triedAddrs);
|
|
886
1242
|
}
|
|
887
|
-
})
|
|
1243
|
+
});
|
|
888
1244
|
} else {
|
|
889
1245
|
logger.debugf('Do not retry RPCs since cluster switch is in progress');
|
|
890
1246
|
}
|