Skip to content

Commit 4a46766

Browse files
committed
feat(cluster): support update startupNodes in clusterRetryStrategy
1 parent 4d04fc2 commit 4a46766

File tree

4 files changed

+36
-42
lines changed

4 files changed

+36
-42
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,14 @@ but a few so that if one is unreachable the client will try the next one, and th
658658
return delay;
659659
}
660660
```
661+
It' possible to modify the `startupNodes` property in order to switch to another set of nodes here:
662+
663+
```javascript
664+
function (times) {
665+
this.startupNodes = [{ port: 6790, host: '127.0.0.1' }];
666+
return Math.min(100 + times * 2, 2000);
667+
}
668+
```
661669

662670
* `enableOfflineQueue`: Similar to the `enableOfflineQueue` option of `Redis` class.
663671
* `enableReadyCheck`: When enabled, "ready" event will only be emitted when `CLUSTER INFO` command

lib/cluster/connection_pool.js

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var util = require('util');
4+
var utils = require('../utils');
45
var EventEmitter = require('events').EventEmitter;
56
var _ = require('lodash');
67
var Redis = require('../redis');
@@ -77,7 +78,7 @@ ConnectionPool.prototype.findOrCreate = function (node, readOnly) {
7778
this.emit('+node', redis);
7879
}
7980

80-
return this.nodes.all[node.key];
81+
return redis;
8182
};
8283

8384
/**
@@ -89,11 +90,26 @@ ConnectionPool.prototype.findOrCreate = function (node, readOnly) {
8990
*/
9091
ConnectionPool.prototype.reset = function (nodes) {
9192
var newNodes = {};
92-
for (var i = 0; i < nodes.length; i++) {
93-
var node = nodes[i];
94-
node.key = node.host + ':' + node.port;
95-
newNodes[node.key] = node;
96-
}
93+
nodes.forEach(function (node) {
94+
var options = {};
95+
if (typeof node === 'object') {
96+
_.defaults(options, node);
97+
} else if (typeof node === 'string') {
98+
_.defaults(options, utils.parseURL(node));
99+
} else if (typeof node === 'number') {
100+
options.port = node;
101+
} else {
102+
throw new Error('Invalid argument ' + node);
103+
}
104+
if (typeof options.port === 'string') {
105+
options.port = parseInt(options.port, 10);
106+
}
107+
delete options.db;
108+
109+
options.key = options.host + ':' + options.port;
110+
newNodes[options.key] = options;
111+
});
112+
97113
var _this = this;
98114
Object.keys(this.nodes.all).forEach(function (key) {
99115
if (!newNodes[key]) {

lib/cluster/index.js

+6-22
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,8 @@ function Cluster(startupNodes, options) {
4949
'". Expected "all", "master", "slave" or a custom function');
5050
}
5151

52-
if (!Array.isArray(startupNodes) || startupNodes.length === 0) {
53-
throw new Error('`startupNodes` should contain at least one node.');
54-
}
55-
5652
this.connectionPool = new ConnectionPool(this.options.redisOptions);
57-
this.startupNodes = startupNodes.map(function (node) {
58-
var options = {};
59-
if (typeof node === 'object') {
60-
_.defaults(options, node);
61-
} else if (typeof node === 'string') {
62-
_.defaults(options, utils.parseURL(node));
63-
} else if (typeof node === 'number') {
64-
options.port = node;
65-
} else {
66-
throw new Error('Invalid argument ' + node);
67-
}
68-
if (typeof options.port === 'string') {
69-
options.port = parseInt(options.port, 10);
70-
}
71-
delete options.db;
72-
return options;
73-
});
53+
this.startupNodes = startupNodes;
7454

7555
var _this = this;
7656
this.connectionPool.on('-node', function (redis) {
@@ -151,6 +131,10 @@ Cluster.prototype.connect = function () {
151131
}
152132
this.setStatus('connecting');
153133

134+
if (!Array.isArray(this.startupNodes) || this.startupNodes.length === 0) {
135+
throw new Error('`startupNodes` should contain at least one node.');
136+
}
137+
154138
this.connectionPool.reset(this.startupNodes);
155139

156140
var closeListener;
@@ -183,7 +167,7 @@ Cluster.prototype.connect = function () {
183167
this.once('close', function () {
184168
var retryDelay;
185169
if (!this.manuallyClosing && typeof this.options.clusterRetryStrategy === 'function') {
186-
retryDelay = this.options.clusterRetryStrategy(++this.retryAttempts);
170+
retryDelay = this.options.clusterRetryStrategy.call(this, ++this.retryAttempts);
187171
}
188172
if (typeof retryDelay === 'number') {
189173
this.setStatus('reconnecting');

test/unit/cluster.js

-14
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,6 @@ describe('cluster', function () {
2222
expect(cluster.options).to.have.property('scaleReads', 'master');
2323
});
2424

25-
it('should throw when startupNodes is not an array or is empty', function () {
26-
expect(function () {
27-
new Cluster();
28-
}).to.throw(/startupNodes/);
29-
30-
expect(function () {
31-
new Cluster([]);
32-
}).to.throw(/startupNodes/);
33-
34-
expect(function () {
35-
new Cluster([{}]);
36-
}).to.not.throw(/startupNodes/);
37-
});
38-
3925
describe('#executeFailoverCommands', function () {
4026
it('should execute the commands', function (done) {
4127
var cluster = {

0 commit comments

Comments
 (0)