mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Library to follow the leader
This commit is contained in:
committed by
Emily Stark
parent
9ab15d4c29
commit
da4ed0697c
1
packages/follower-livedata/.gitignore
vendored
Normal file
1
packages/follower-livedata/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.build*
|
||||
128
packages/follower-livedata/follower.js
Normal file
128
packages/follower-livedata/follower.js
Normal file
@@ -0,0 +1,128 @@
|
||||
Follower = {
|
||||
|
||||
connect: function (urlSet) {
|
||||
if (typeof urlSet === 'string') {
|
||||
urlSet = _.map(urlSet.split(','), function (url) {return url.trim();});
|
||||
}
|
||||
var electorTries = {};
|
||||
// start each elector as untried/assumed connectable.
|
||||
_.each(urlSet, function (url) {
|
||||
electorTries[url] = 0;
|
||||
});
|
||||
var tryingUrl = null;
|
||||
var conn = null;
|
||||
var leader = null;
|
||||
var connected = null;
|
||||
var intervalHandle = null;
|
||||
|
||||
var findFewestTries = function () {
|
||||
var min = 10000;
|
||||
var minElector = null;
|
||||
_.each(electorTries, function (tries, elector) {
|
||||
if (tries < min) {
|
||||
min = tries;
|
||||
minElector = elector;
|
||||
}
|
||||
});
|
||||
return minElector;
|
||||
};
|
||||
|
||||
var updateElectorate = function (res) {
|
||||
leader = res.leader;
|
||||
_.each(electorTries, function (state, elector) {
|
||||
if (!_.contains(res.electorate, elector)) {
|
||||
delete electorTries[elector];
|
||||
}
|
||||
});
|
||||
_.each(res.electorate, function (elector) {
|
||||
if (typeof electorTries[elector] === 'undefined') {
|
||||
electorTries[elector] = 0; // we haven't heard of this elector yet.
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var tryElector = function (url) {
|
||||
url = url || findFewestTries();
|
||||
if (conn) {
|
||||
conn._reconnectImpl({
|
||||
url: url
|
||||
});
|
||||
} else {
|
||||
conn = DDP.connect(url);
|
||||
conn._reconnectImpl = conn.reconnect;
|
||||
}
|
||||
|
||||
if (tryingUrl) {
|
||||
electorTries[tryingUrl]++;
|
||||
} else {
|
||||
tryingUrl = url;
|
||||
conn.call('getElectorate', function (err, res) {
|
||||
connected = tryingUrl;
|
||||
tryingUrl = null;
|
||||
if (err) {
|
||||
electorTries[url]++;
|
||||
return;
|
||||
}
|
||||
// we got an answer! Connected!
|
||||
electorTries[url] = 0;
|
||||
if (res.leader === url) {
|
||||
// we're good.
|
||||
|
||||
} else {
|
||||
// let's connect to the leader anyway, if we think it
|
||||
// is connectable.
|
||||
if (electorTries[res.leader] == 0) {
|
||||
tryElector(res.leader);
|
||||
|
||||
} else {
|
||||
// XXX: leader is probably down, we're probably going to elect
|
||||
// soon. Wait for the next round.
|
||||
}
|
||||
|
||||
}
|
||||
updateElectorate(res);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
tryElector();
|
||||
|
||||
|
||||
var monitorConnection = function () {
|
||||
return Meteor.setInterval(function () {
|
||||
if (conn.status().status !== 'connected' || connected !== leader) {
|
||||
tryElector();
|
||||
} else {
|
||||
conn.call('getElectorate', function (err, res) {
|
||||
if (err) {
|
||||
electorTries[connected]++;
|
||||
tryElector();
|
||||
} else {
|
||||
updateElectorate(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 5*1000); // every 5 seconds
|
||||
};
|
||||
|
||||
intervalHandle = monitorConnection();
|
||||
|
||||
|
||||
var prevDisconnect = conn.disconnect;
|
||||
conn.disconnect = function () {
|
||||
if (intervalHandle)
|
||||
Meteor.clearInterval(intervalHandle);
|
||||
intervalHandle = null;
|
||||
prevDisconnect.apply(conn);
|
||||
};
|
||||
|
||||
conn.reconnect = function () {
|
||||
if (!intervalHandle)
|
||||
intervalHandle = monitorConnection();
|
||||
conn._reconnectImpl.apply(conn, arguments);
|
||||
};
|
||||
|
||||
return conn;
|
||||
|
||||
}
|
||||
};
|
||||
9
packages/follower-livedata/package.js
Normal file
9
packages/follower-livedata/package.js
Normal file
@@ -0,0 +1,9 @@
|
||||
Package.describe({
|
||||
summary: "Maintain a connection to the leader of an election set"
|
||||
});
|
||||
|
||||
Package.on_use(function (api) {
|
||||
api.use(['underscore', 'livedata', 'ejson']);
|
||||
api.add_files(['follower.js'], 'server');
|
||||
api.export('Follower');
|
||||
});
|
||||
Reference in New Issue
Block a user