do-node-balancer
Version:
Node.js load balancer for digitalocean using tags
87 lines (77 loc) • 1.92 kB
JavaScript
const _ = require('lodash');
module.exports = ({ joi, doTags, doRequest, opts }) => {
const servers = {};
const doResp = joi.object().keys({
droplets: joi.array().min(1).required(),
});
function updateServers() {
doTags.forEach((tag) => {
doRequest.getDropletsByTag(tag)
.then(body => doResp.validate(body, { allowUnknown: true }))
.then(({ droplets }) =>
droplets
.map(droplet => _.get(droplet, 'networks.v4', null))
.filter(nets => Array.isArray(nets))
.map(nets => nets
.filter(net => net instanceof Object)
.find(net => net.type === 'public'),
)
.filter(net => net.ip_address)
.map(net => ({
...net,
failCount: 0,
})),
)
.then((result) => {
if (result) {
servers[tag] = result;
} else {
throw new Error('No Result');
}
})
.catch(err => console.log('error ', err));
});
}
if (opts.doUpdateTime > 0) {
updateServers();
setInterval(updateServers, opts.doUpdateTime);
}
function getServer(tags) {
if (!Array.isArray(tags)) {
return null;
}
return _.sample(
_.intersection(
...tags
.map(tag => (
servers[tag] && servers[tag].map(taggedServer => taggedServer.ip_address)) || [],
)
.map(addrs => addrs || []),
),
) || null;
}
function getServerList() {
return servers;
}
function reportFailure(target) {
if (!(target instanceof Object && target.tags && Array.isArray(target.tags) && target.host)) {
return;
}
target.tags.forEach((tag) => {
const suspects = servers[tag];
const crimeIndex = _.findIndex(suspects, ['ip_address', target.host]);
if (crimeIndex > 0) {
suspects[crimeIndex].failCount += 1;
if (suspects[crimeIndex].failCount > opts.maxFailCount) {
suspects.splice(crimeIndex, 1);
}
}
});
}
return {
getServer,
getServerList,
reportFailure,
updateServers,
};
};