Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/externals/javelin/lib/Leader.js
| Show All 28 Lines | |||||
| */ | */ | ||||
| JX.install('Leader', { | JX.install('Leader', { | ||||
| events: ['onBecomeLeader', 'onReceiveBroadcast'], | events: ['onBecomeLeader', 'onReceiveBroadcast'], | ||||
| statics: { | statics: { | ||||
| _interval: null, | _interval: null, | ||||
| _timeout: null, | |||||
| _broadcastKey: 'JX.Leader.broadcast', | _broadcastKey: 'JX.Leader.broadcast', | ||||
| _leaderKey: 'JX.Leader.id', | _leaderKey: 'JX.Leader.id', | ||||
| /** | /** | ||||
| * Tracks leadership state. Since leadership election is asynchronous, | * Tracks leadership state. Since leadership election is asynchronous, | ||||
| * we can't expose this directly without inconsistent behavior. | * we can't expose this directly without inconsistent behavior. | ||||
| */ | */ | ||||
| Show All 13 Lines | statics: { | ||||
| _seenList: [], | _seenList: [], | ||||
| /** | /** | ||||
| * Elect a leader, triggering leadership callbacks if they are registered. | * Elect a leader, triggering leadership callbacks if they are registered. | ||||
| */ | */ | ||||
| start: function() { | start: function() { | ||||
| var self = JX.Leader; | var self = JX.Leader; | ||||
| self.callIfLeader(JX.bag); | self.call(JX.bag); | ||||
| }, | }, | ||||
| /** | /** | ||||
| * Call a method if this tab is the leader. | * Call a method if this tab is the leader. | ||||
| * | * | ||||
| * This is asynchronous because leadership election is asynchronous. If | * This is asynchronous because leadership election is asynchronous. If | ||||
| * the current tab is not the leader after any election takes place, the | * the current tab is not the leader after any election takes place, the | ||||
| * callback will not be invoked. | * callback will not be invoked. | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | _callIf: function(leader_callback, follower_callback) { | ||||
| // tab is closed. | // tab is closed. | ||||
| if (!self._interval && lease.until > now + 10000) { | if (!self._interval && lease.until > now + 10000) { | ||||
| self._interval = window.setInterval(self._write, 5000); | self._interval = window.setInterval(self._write, 5000); | ||||
| } | } | ||||
| self._becomeLeader(); | self._becomeLeader(); | ||||
| leader_callback(); | leader_callback(); | ||||
| } else { | } else { | ||||
| // Set a callback to try to become the leader shortly after the | |||||
| // current lease expires. This lets us recover from cases where the | |||||
| // leader goes missing quickly. | |||||
| if (self._timeoout) { | |||||
| window.clearTimeout(self._timeout); | |||||
| self._timeout = null; | |||||
| } | |||||
| self._timeout = window.setTimeout( | |||||
| self._usurp, | |||||
| (lease.until - now) + 50); | |||||
| follower_callback(); | follower_callback(); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| // If the lease isn't good, try to become the leader. We don't have | // If the lease isn't good, try to become the leader. We don't have | ||||
| // proper locking primitives for this, but can do a relatively good | // proper locking primitives for this, but can do a relatively good | ||||
| // job. The algorithm here is: | // job. The algorithm here is: | ||||
| // | // | ||||
| // - Write our ID, trying to acquire the lease. | // - Write our ID, trying to acquire the lease. | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | _becomeLeader: function() { | ||||
| if (self._isLeader) { | if (self._isLeader) { | ||||
| return; | return; | ||||
| } | } | ||||
| self._isLeader = true; | self._isLeader = true; | ||||
| new JX.Leader().invoke('onBecomeLeader'); | new JX.Leader().invoke('onBecomeLeader'); | ||||
| }, | }, | ||||
| /** | |||||
| * Try to usurp leadership position after a lease expiration. | |||||
| */ | |||||
| _usurp: function() { | |||||
| var self = JX.Leader; | |||||
| self.call(JX.bag); | |||||
| }, | |||||
| /** | /** | ||||
| * Mark a message as seen. | * Mark a message as seen. | ||||
| * | * | ||||
| * We keep a fixed-sized list of recent messages, and let old ones fall | * We keep a fixed-sized list of recent messages, and let old ones fall | ||||
| * off the end after a while. | * off the end after a while. | ||||
| */ | */ | ||||
| _markSeen: function(id) { | _markSeen: function(id) { | ||||
| var self = JX.Leader; | var self = JX.Leader; | ||||
| Show All 11 Lines | |||||