Skip to content

Commit ee90c8c

Browse files
committed
4.8.0
1 parent 3bc74c7 commit ee90c8c

File tree

12 files changed

+382
-182
lines changed

12 files changed

+382
-182
lines changed

dist/es5node/leader-election.js

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
3333

3434
this._lstns = []; // _listeners
3535

36-
this._invs = []; // _intervals
37-
3836
this._dpL = function () {}; // onduplicate listener
3937

4038

@@ -69,7 +67,8 @@ LeaderElection.prototype = {
6967
* false if not.
7068
* @async
7169
*/
72-
applyOnce: function applyOnce() {
70+
applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
71+
isFromFallbackInterval) {
7372
var _this2 = this;
7473

7574
if (this.isLeader) {
@@ -144,18 +143,31 @@ LeaderElection.prototype = {
144143
};
145144

146145
_this2.broadcastChannel.addEventListener('internal', handleMessage);
146+
/**
147+
* If the applyOnce() call came from the fallbackInterval,
148+
* we can assume that the election runs in the background and
149+
* not critical process is waiting for it.
150+
* When this is true, we give the other intances
151+
* more time to answer to messages in the election cycle.
152+
* This makes it less likely to elect duplicate leaders.
153+
* But also it takes longer which is not a problem because we anyway
154+
* run in the background.
155+
*/
156+
157+
158+
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
147159

148160
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
149161
.then(function () {
150-
return Promise.race([(0, _util.sleep)(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
162+
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
151163
return Promise.reject(new Error());
152164
})]);
153165
}) // send again in case another instance was just created
154166
.then(function () {
155167
return _sendMessage(_this2, 'apply');
156168
}) // let others time to respond
157169
.then(function () {
158-
return Promise.race([(0, _util.sleep)(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
170+
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
159171
return Promise.reject(new Error());
160172
})]);
161173
})["catch"](function () {}).then(function () {
@@ -208,12 +220,6 @@ LeaderElection.prototype = {
208220

209221
this._lstns = [];
210222

211-
this._invs.forEach(function (interval) {
212-
return clearInterval(interval);
213-
});
214-
215-
this._invs = [];
216-
217223
this._unl.forEach(function (uFn) {
218224
return uFn.remove();
219225
});
@@ -247,7 +253,6 @@ function _awaitLeadershipOnce(leaderElector) {
247253
}
248254

249255
resolved = true;
250-
clearInterval(interval);
251256
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
252257
res(true);
253258
} // try once now
@@ -257,18 +262,33 @@ function _awaitLeadershipOnce(leaderElector) {
257262
if (leaderElector.isLeader) {
258263
finish();
259264
}
260-
}); // try on fallbackInterval
265+
});
266+
/**
267+
* Try on fallbackInterval
268+
* @recursive
269+
*/
270+
271+
var tryOnFallBack = function tryOnFallBack() {
272+
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
273+
if (leaderElector.isDead || resolved) {
274+
return;
275+
}
261276

262-
var interval = setInterval(function () {
263-
leaderElector.applyOnce().then(function () {
264277
if (leaderElector.isLeader) {
265278
finish();
279+
} else {
280+
return leaderElector.applyOnce(true).then(function () {
281+
if (leaderElector.isLeader) {
282+
finish();
283+
} else {
284+
tryOnFallBack();
285+
}
286+
});
266287
}
267288
});
268-
}, leaderElector._options.fallbackInterval);
269-
270-
leaderElector._invs.push(interval); // try when other leader dies
289+
};
271290

291+
tryOnFallBack(); // try when other leader dies
272292

273293
var whenDeathListener = function whenDeathListener(msg) {
274294
if (msg.context === 'leader' && msg.action === 'death') {

dist/esbrowser/leader-election.js

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
2424

2525
this._lstns = []; // _listeners
2626

27-
this._invs = []; // _intervals
28-
2927
this._dpL = function () {}; // onduplicate listener
3028

3129

@@ -60,7 +58,8 @@ LeaderElection.prototype = {
6058
* false if not.
6159
* @async
6260
*/
63-
applyOnce: function applyOnce() {
61+
applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
62+
isFromFallbackInterval) {
6463
var _this2 = this;
6564

6665
if (this.isLeader) {
@@ -135,18 +134,31 @@ LeaderElection.prototype = {
135134
};
136135

137136
_this2.broadcastChannel.addEventListener('internal', handleMessage);
137+
/**
138+
* If the applyOnce() call came from the fallbackInterval,
139+
* we can assume that the election runs in the background and
140+
* not critical process is waiting for it.
141+
* When this is true, we give the other intances
142+
* more time to answer to messages in the election cycle.
143+
* This makes it less likely to elect duplicate leaders.
144+
* But also it takes longer which is not a problem because we anyway
145+
* run in the background.
146+
*/
147+
148+
149+
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
138150

139151
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
140152
.then(function () {
141-
return Promise.race([sleep(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
153+
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
142154
return Promise.reject(new Error());
143155
})]);
144156
}) // send again in case another instance was just created
145157
.then(function () {
146158
return _sendMessage(_this2, 'apply');
147159
}) // let others time to respond
148160
.then(function () {
149-
return Promise.race([sleep(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
161+
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
150162
return Promise.reject(new Error());
151163
})]);
152164
})["catch"](function () {}).then(function () {
@@ -199,12 +211,6 @@ LeaderElection.prototype = {
199211

200212
this._lstns = [];
201213

202-
this._invs.forEach(function (interval) {
203-
return clearInterval(interval);
204-
});
205-
206-
this._invs = [];
207-
208214
this._unl.forEach(function (uFn) {
209215
return uFn.remove();
210216
});
@@ -238,7 +244,6 @@ function _awaitLeadershipOnce(leaderElector) {
238244
}
239245

240246
resolved = true;
241-
clearInterval(interval);
242247
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
243248
res(true);
244249
} // try once now
@@ -248,18 +253,33 @@ function _awaitLeadershipOnce(leaderElector) {
248253
if (leaderElector.isLeader) {
249254
finish();
250255
}
251-
}); // try on fallbackInterval
256+
});
257+
/**
258+
* Try on fallbackInterval
259+
* @recursive
260+
*/
261+
262+
var tryOnFallBack = function tryOnFallBack() {
263+
return sleep(leaderElector._options.fallbackInterval).then(function () {
264+
if (leaderElector.isDead || resolved) {
265+
return;
266+
}
252267

253-
var interval = setInterval(function () {
254-
leaderElector.applyOnce().then(function () {
255268
if (leaderElector.isLeader) {
256269
finish();
270+
} else {
271+
return leaderElector.applyOnce(true).then(function () {
272+
if (leaderElector.isLeader) {
273+
finish();
274+
} else {
275+
tryOnFallBack();
276+
}
277+
});
257278
}
258279
});
259-
}, leaderElector._options.fallbackInterval);
260-
261-
leaderElector._invs.push(interval); // try when other leader dies
280+
};
262281

282+
tryOnFallBack(); // try when other leader dies
263283

264284
var whenDeathListener = function whenDeathListener(msg) {
265285
if (msg.context === 'leader' && msg.action === 'death') {

dist/esnode/leader-election.js

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
2424

2525
this._lstns = []; // _listeners
2626

27-
this._invs = []; // _intervals
28-
2927
this._dpL = function () {}; // onduplicate listener
3028

3129

@@ -60,7 +58,8 @@ LeaderElection.prototype = {
6058
* false if not.
6159
* @async
6260
*/
63-
applyOnce: function applyOnce() {
61+
applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
62+
isFromFallbackInterval) {
6463
var _this2 = this;
6564

6665
if (this.isLeader) {
@@ -135,18 +134,31 @@ LeaderElection.prototype = {
135134
};
136135

137136
_this2.broadcastChannel.addEventListener('internal', handleMessage);
137+
/**
138+
* If the applyOnce() call came from the fallbackInterval,
139+
* we can assume that the election runs in the background and
140+
* not critical process is waiting for it.
141+
* When this is true, we give the other intances
142+
* more time to answer to messages in the election cycle.
143+
* This makes it less likely to elect duplicate leaders.
144+
* But also it takes longer which is not a problem because we anyway
145+
* run in the background.
146+
*/
147+
148+
149+
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
138150

139151
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
140152
.then(function () {
141-
return Promise.race([sleep(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
153+
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
142154
return Promise.reject(new Error());
143155
})]);
144156
}) // send again in case another instance was just created
145157
.then(function () {
146158
return _sendMessage(_this2, 'apply');
147159
}) // let others time to respond
148160
.then(function () {
149-
return Promise.race([sleep(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
161+
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
150162
return Promise.reject(new Error());
151163
})]);
152164
})["catch"](function () {}).then(function () {
@@ -199,12 +211,6 @@ LeaderElection.prototype = {
199211

200212
this._lstns = [];
201213

202-
this._invs.forEach(function (interval) {
203-
return clearInterval(interval);
204-
});
205-
206-
this._invs = [];
207-
208214
this._unl.forEach(function (uFn) {
209215
return uFn.remove();
210216
});
@@ -238,7 +244,6 @@ function _awaitLeadershipOnce(leaderElector) {
238244
}
239245

240246
resolved = true;
241-
clearInterval(interval);
242247
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
243248
res(true);
244249
} // try once now
@@ -248,18 +253,33 @@ function _awaitLeadershipOnce(leaderElector) {
248253
if (leaderElector.isLeader) {
249254
finish();
250255
}
251-
}); // try on fallbackInterval
256+
});
257+
/**
258+
* Try on fallbackInterval
259+
* @recursive
260+
*/
261+
262+
var tryOnFallBack = function tryOnFallBack() {
263+
return sleep(leaderElector._options.fallbackInterval).then(function () {
264+
if (leaderElector.isDead || resolved) {
265+
return;
266+
}
252267

253-
var interval = setInterval(function () {
254-
leaderElector.applyOnce().then(function () {
255268
if (leaderElector.isLeader) {
256269
finish();
270+
} else {
271+
return leaderElector.applyOnce(true).then(function () {
272+
if (leaderElector.isLeader) {
273+
finish();
274+
} else {
275+
tryOnFallBack();
276+
}
277+
});
257278
}
258279
});
259-
}, leaderElector._options.fallbackInterval);
260-
261-
leaderElector._invs.push(interval); // try when other leader dies
280+
};
262281

282+
tryOnFallBack(); // try when other leader dies
263283

264284
var whenDeathListener = function whenDeathListener(msg) {
265285
if (msg.context === 'leader' && msg.action === 'death') {

0 commit comments

Comments
 (0)