diff --git a/config.js b/config.js index ec0caf2c..c375f51e 100644 --- a/config.js +++ b/config.js @@ -69,6 +69,7 @@ Config.prototype._seed = function _seed(seed) { return val instanceof RegExp; }); }, 'expected to be array of RegExp objects'); + seedOrDefault('maxJoinAttempts', 50, numValidator); function seedOrDefault(name, defaultVal, validator, reason) { var seedVal = seed[name]; @@ -91,4 +92,8 @@ Config.prototype._seed = function _seed(seed) { } }; +function numValidator(maybeNum) { + return typeof maybeNum === 'number' && !isNaN(maybeNum); +} + module.exports = Config; diff --git a/lib/swim/join-sender.js b/lib/swim/join-sender.js index 2ccb4ae1..696d3b49 100644 --- a/lib/swim/join-sender.js +++ b/lib/swim/join-sender.js @@ -63,7 +63,6 @@ var JOIN_TIMEOUT = 1000; // provisioned cluster // - Trying forever is futile var MAX_JOIN_DURATION = 120000; -var MAX_JOIN_ATTEMPTS = 50; var PARALLELISM_FACTOR = 2; function isSingleNodeCluster(ringpop) { @@ -113,11 +112,6 @@ function JoinCluster(opts) { this.maxJoinDuration = numOrDefault(opts.maxJoinDuration, MAX_JOIN_DURATION); - // We want to abort the joining process if we have failed - // a certain number of times. - this.maxJoinAttempts = numOrDefault(opts.maxJoinAttempts, - MAX_JOIN_ATTEMPTS); - // We do not want to retry joining as hard as we can. We // want to have some fixed backoff applied before we try // to join again @@ -226,6 +220,7 @@ JoinCluster.prototype.join = function join(callback) { var numFailed = 0; var startTime = Date.now(); var calledBack = false; + var maxJoinAttempts = this.ringpop.config.get('maxJoinAttempts'); function onJoin(err, nodes) { if (calledBack) { @@ -275,11 +270,11 @@ JoinCluster.prototype.join = function join(callback) { calledBack = true; callback(null, nodesJoined); - } else if (numFailed >= self.maxJoinAttempts) { + } else if (numFailed >= maxJoinAttempts) { self.ringpop.logger.warn('ringpop max join attempts exceeded', { local: self.ringpop.whoami(), joinAttempts: numFailed, - maxJoinAttempts: self.maxJoinAttempts, + maxJoinAttempts: maxJoinAttempts, numJoined: numJoined, numFailed: numFailed, startTime: startTime @@ -288,7 +283,7 @@ JoinCluster.prototype.join = function join(callback) { calledBack = true; callback(JoinAttemptsExceededError({ joinAttempts: numFailed, - maxJoinAttempts: self.maxJoinAttempts + maxJoinAttempts: maxJoinAttempts })); return; } else { diff --git a/test/integration/join-test.js b/test/integration/join-test.js index d7a3f621..13e726d9 100644 --- a/test/integration/join-test.js +++ b/test/integration/join-test.js @@ -121,7 +121,7 @@ testRingpopCluster({ testRingpopCluster({ size: 2, tap: function tap(cluster) { - cluster[1].channel.register('/protocol/join', function protocolJoin(req, res, head, body) { + cluster[1].channel.register('/protocol/join', function protocolJoin(req, res) { setTimeout(function onTimeout() { cluster[0].destroy(); @@ -145,3 +145,20 @@ testRingpopCluster({ assert.ok(cluster[1].isReady, 'node two is ready'); assert.end(); }); + +// This is a 3-node test. All nodes need to join a minimum of 2 other nodes. +// Node 0 has been blacklisted by Node 1 so it can't possibly join 2 others. +// Node 0's bootstrap is expected to fail. +testRingpopCluster({ + size: 3, + tap: function tap(cluster) { + // This'll make Node 0's join fail faster + cluster[0].config.set('maxJoinAttempts', 1); + cluster[1].config.set('joinBlacklist', [/127.0.0.1:10000/]); + } +}, 'join blacklist', function t(bootRes, cluster, assert) { + assert.notok(cluster[0].isReady, 'node one is not ready'); + assert.ok(cluster[1].isReady, 'node two is ready'); + assert.ok(cluster[2].isReady, 'node three is ready'); + assert.end(); +}); diff --git a/test/unit/config_test.js b/test/unit/config_test.js index 4abd13c0..a06e36d5 100644 --- a/test/unit/config_test.js +++ b/test/unit/config_test.js @@ -90,3 +90,12 @@ test('validates joinBlacklist seed', function t(assert) { 'uses seed blacklist'); assert.end(); }); + +test('validates num', function t(assert) { + var config = new Config(null, { + 'maxJoinAttempts': 'notanum' + }); + assert.equals(50, config.get('maxJoinAttempts'), + 'uses default'); + assert.end(); +});