diff --git a/README.md b/README.md index 334117b9..7129fc92 100644 --- a/README.md +++ b/README.md @@ -658,6 +658,14 @@ but a few so that if one is unreachable the client will try the next one, and th return delay; } ``` + It' possible to modify the `startupNodes` property in order to switch to another set of nodes here: + + ```javascript + function (times) { + this.startupNodes = [{ port: 6790, host: '127.0.0.1' }]; + return Math.min(100 + times * 2, 2000); + } + ``` * `enableOfflineQueue`: Similar to the `enableOfflineQueue` option of `Redis` class. * `enableReadyCheck`: When enabled, "ready" event will only be emitted when `CLUSTER INFO` command diff --git a/lib/cluster/connection_pool.js b/lib/cluster/connection_pool.js index 2810d6bc..e43655be 100644 --- a/lib/cluster/connection_pool.js +++ b/lib/cluster/connection_pool.js @@ -1,6 +1,7 @@ 'use strict'; var util = require('util'); +var utils = require('../utils'); var EventEmitter = require('events').EventEmitter; var _ = require('lodash'); var Redis = require('../redis'); @@ -77,7 +78,7 @@ ConnectionPool.prototype.findOrCreate = function (node, readOnly) { this.emit('+node', redis); } - return this.nodes.all[node.key]; + return redis; }; /** @@ -89,11 +90,26 @@ ConnectionPool.prototype.findOrCreate = function (node, readOnly) { */ ConnectionPool.prototype.reset = function (nodes) { var newNodes = {}; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - node.key = node.host + ':' + node.port; - newNodes[node.key] = node; - } + nodes.forEach(function (node) { + var options = {}; + if (typeof node === 'object') { + _.defaults(options, node); + } else if (typeof node === 'string') { + _.defaults(options, utils.parseURL(node)); + } else if (typeof node === 'number') { + options.port = node; + } else { + throw new Error('Invalid argument ' + node); + } + if (typeof options.port === 'string') { + options.port = parseInt(options.port, 10); + } + delete options.db; + + options.key = options.host + ':' + options.port; + newNodes[options.key] = options; + }); + var _this = this; Object.keys(this.nodes.all).forEach(function (key) { if (!newNodes[key]) { diff --git a/lib/cluster/index.js b/lib/cluster/index.js index 5ea0af20..247d7202 100644 --- a/lib/cluster/index.js +++ b/lib/cluster/index.js @@ -49,28 +49,8 @@ function Cluster(startupNodes, options) { '". Expected "all", "master", "slave" or a custom function'); } - if (!Array.isArray(startupNodes) || startupNodes.length === 0) { - throw new Error('`startupNodes` should contain at least one node.'); - } - this.connectionPool = new ConnectionPool(this.options.redisOptions); - this.startupNodes = startupNodes.map(function (node) { - var options = {}; - if (typeof node === 'object') { - _.defaults(options, node); - } else if (typeof node === 'string') { - _.defaults(options, utils.parseURL(node)); - } else if (typeof node === 'number') { - options.port = node; - } else { - throw new Error('Invalid argument ' + node); - } - if (typeof options.port === 'string') { - options.port = parseInt(options.port, 10); - } - delete options.db; - return options; - }); + this.startupNodes = startupNodes; var _this = this; this.connectionPool.on('-node', function (redis) { @@ -151,6 +131,10 @@ Cluster.prototype.connect = function () { } this.setStatus('connecting'); + if (!Array.isArray(this.startupNodes) || this.startupNodes.length === 0) { + throw new Error('`startupNodes` should contain at least one node.'); + } + this.connectionPool.reset(this.startupNodes); var closeListener; @@ -183,7 +167,7 @@ Cluster.prototype.connect = function () { this.once('close', function () { var retryDelay; if (!this.manuallyClosing && typeof this.options.clusterRetryStrategy === 'function') { - retryDelay = this.options.clusterRetryStrategy(++this.retryAttempts); + retryDelay = this.options.clusterRetryStrategy.call(this, ++this.retryAttempts); } if (typeof retryDelay === 'number') { this.setStatus('reconnecting'); diff --git a/test/unit/cluster.js b/test/unit/cluster.js index 76aa9af2..770509e3 100644 --- a/test/unit/cluster.js +++ b/test/unit/cluster.js @@ -22,20 +22,6 @@ describe('cluster', function () { expect(cluster.options).to.have.property('scaleReads', 'master'); }); - it('should throw when startupNodes is not an array or is empty', function () { - expect(function () { - new Cluster(); - }).to.throw(/startupNodes/); - - expect(function () { - new Cluster([]); - }).to.throw(/startupNodes/); - - expect(function () { - new Cluster([{}]); - }).to.not.throw(/startupNodes/); - }); - describe('#executeFailoverCommands', function () { it('should execute the commands', function (done) { var cluster = {