Skip to content

Commit

Permalink
4.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
pubkey committed Dec 2, 2021
1 parent db847eb commit b41ed92
Show file tree
Hide file tree
Showing 28 changed files with 1,257 additions and 699 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## X.X.X (comming soon)

## 4.6.0 (2 December 2021)

Other:
- Added `broadcastChannel.id()` for debugging

Expand Down
14 changes: 13 additions & 1 deletion dist/es5node/broadcast-channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.BroadcastChannel = void 0;
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;

Expand All @@ -13,7 +13,18 @@ var _methodChooser = require("./method-chooser.js");

var _options = require("./options.js");

/**
* Contains all open channels,
* used in tests to ensure everything is closed.
*/
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;

var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;

if (ENFORCED_OPTIONS) {
Expand Down Expand Up @@ -154,6 +165,7 @@ BroadcastChannel.prototype = {
return;
}

OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
Expand Down
6 changes: 6 additions & 0 deletions dist/es5node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Object.defineProperty(exports, "BroadcastChannel", {
return _broadcastChannel.BroadcastChannel;
}
});
Object.defineProperty(exports, "OPEN_BROADCAST_CHANNELS", {
enumerable: true,
get: function get() {
return _broadcastChannel.OPEN_BROADCAST_CHANNELS;
}
});
Object.defineProperty(exports, "beLeader", {
enumerable: true,
get: function get() {
Expand Down
172 changes: 104 additions & 68 deletions dist/es5node/leader-election.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,14 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
this.isDead = false;
this.token = (0, _util.randomToken)();
/**
* _isApplying
* Only set when a leader application is
* running at the moment.
* @type {Promise<any> | null}
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/

this._isApl = false; // _isApplying
this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls

this._reApply = false; // things to clean up
this._aplQC = 0; // things to clean up

this._unl = []; // _unloads

Expand Down Expand Up @@ -65,6 +64,11 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
};

LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
applyOnce: function applyOnce() {
var _this2 = this;

Expand All @@ -73,82 +77,113 @@ LeaderElection.prototype = {
}

if (this.isDead) {
return _util.PROMISE_RESOLVED_FALSE;
} // do nothing if already running
return (0, _util.sleep)(0, false);
}
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/


if (this._isApl) {
this._reApply = true;
return (0, _util.sleep)(0, false);
if (this._aplQC > 1) {
return this._aplQ;
}
/**
* Add a new apply-run
*/

var stopCriteria = false;
var recieved = [];

var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
* Directly return if a previous run
* has already elected a leader.
*/
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}

if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
// other has higher token, stop applying
stopCriteria = true;
}
}
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
* Resolves when a stop criteria is reached.
* Uses as a performance shortcut so we do not
* have to await the responseTime when it is already clear
* that the election failed.
*/

if (msg.action === 'tell') {
// other is already leader
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
_this2.hasLeader = true;
res();
};
});
var recieved = [];

var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);

if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
/**
* other has higher token
* -> stop applying and let other become leader.
*/
stopCriteriaPromiseResolve();
}
}

if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
_this2.hasLeader = true;
}
}
}
};
};

this.broadcastChannel.addEventListener('internal', handleMessage);
_this2.broadcastChannel.addEventListener('internal', handleMessage);

var applyPromise = _sendMessage(this, 'apply') // send out that this one is applying
.then(function () {
return (0, _util.sleep)(_this2._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) {
return Promise.reject(new Error());
} else {
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
}) // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
}
}).then(function () {
return (0, _util.sleep)(_this2._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) {
return Promise.reject(new Error());
} else {
return _sendMessage(_this2);
}
}) // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(_this2._options.responseTime / 2), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);

if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
return true;
});
} else {
// other is leader
return false;
}
});

return applyPromise;
};

this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
}).then(function () {
return beLeader(_this2);
}) // no one disagreed -> this one is now leader
.then(function () {
return true;
})["catch"](function () {
return false;
}) // apply not successfull
.then(function (success) {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);

_this2._isApl = false;

if (!success && _this2._reApply) {
_this2._reApply = false;
return _this2.applyOnce();
} else {
return success;
}
_this2._aplQC = _this2._aplQC - 1;
});
return this._aplQ.then(function () {
return _this2.isLeader;
});

this._isApl = applyPromise;
return applyPromise;
},
awaitLeadership: function awaitLeadership() {
if (
Expand Down Expand Up @@ -225,6 +260,7 @@ function _awaitLeadershipOnce(leaderElector) {
}); // try on fallbackInterval

var interval = setInterval(function () {
console.log('applyOnce via fallbackInterval');
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
Expand Down
5 changes: 4 additions & 1 deletion dist/es5node/methods/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,10 @@ function postMessage(channelState, messageJson) {


function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) return; // disabled
if (!state.options.node.useFastPath) {
// disabled
return;
}

var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
Expand Down
4 changes: 3 additions & 1 deletion dist/es5node/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isNode = exports.PROMISE_RESOLVED_VOID = exports.PROMISE_RESOLVED_FALSE = void 0;
exports.isNode = exports.PROMISE_RESOLVED_VOID = exports.PROMISE_RESOLVED_TRUE = exports.PROMISE_RESOLVED_FALSE = void 0;
exports.isPromise = isPromise;
exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
Expand All @@ -23,6 +23,8 @@ function isPromise(obj) {

var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;

Expand Down
11 changes: 11 additions & 0 deletions dist/esbrowser/broadcast-channel.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { isPromise, PROMISE_RESOLVED_FALSE, PROMISE_RESOLVED_VOID } from './util.js';
import { chooseMethod } from './method-chooser.js';
import { fillOptionsWithDefaults } from './options.js';
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
*/

export var OPEN_BROADCAST_CHANNELS = new Set();
var lastId = 0;
export var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;

if (ENFORCED_OPTIONS) {
Expand Down Expand Up @@ -137,6 +147,7 @@ BroadcastChannel.prototype = {
return;
}

OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : PROMISE_RESOLVED_VOID;
this._onML = null;
Expand Down
2 changes: 1 addition & 1 deletion dist/esbrowser/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { BroadcastChannel, clearNodeFolder, enforceOptions } from './broadcast-channel';
export { BroadcastChannel, clearNodeFolder, enforceOptions, OPEN_BROADCAST_CHANNELS } from './broadcast-channel';
export { createLeaderElection, beLeader } from './leader-election';
Loading

0 comments on commit b41ed92

Please sign in to comment.