do-node-balancer
Version:
Node.js load balancer for digitalocean using tags
125 lines (112 loc) • 2.78 kB
JavaScript
const httpProxy = require('http-proxy');
const DigitalOcean = require('./digitalocean');
const https = require('https');
const assert = require('assert');
const request = require('./request.js');
const joi = require('joi');
module.exports = ({ doToken, doTags, options }) => {
const opts = {
maxFailCount: 5,
doUpdateTime: 1000 * 60 * 10,
...options,
};
const doRequest = request(doToken);
const doProvider = DigitalOcean({
joi,
doTags,
doRequest,
opts,
});
const agent = new https.Agent({
maxSockets: 1000,
keepAlive: true,
keepAliveMsecs: 3000,
});
const proxy = httpProxy.createProxy({
agent,
ws: true,
});
function displayErrorPage(res) {
if (opts.failurePage) {
res.write(opts.failurePage);
return res.end();
}
return res.end('Something went wrong -- proxy error');
}
proxy.on('error', (e, req, res) => {
// Do not report failures for now, this needs to be thought through
// doProvider.reportFailure(req.target);
console.log('Proxy error event', e);
displayErrorPage(res);
});
const balance = (req, res, params) => {
const par = params || {};
assert((par instanceof Object), 'params must be an object or unspecified');
const { tags, port, address } = params;
const host = address || doProvider.getServer(tags);
if (!host) {
res.end('Something went wrong -- host not found');
return;
}
const MAX_ATTEMPTS = 3;
let attempt = 1;
req.url = req.originalUrl;
req.target = {
host,
tags,
port,
protocol: 'https:',
};
const webOpts = {
target: req.target,
secure: true,
};
const redirect = () => {
// Proxy 'error' event listener won't fire if we provide an error callback here.
proxy.web(req, res, webOpts, (err) => {
console.log('Web error callback', err);
if (attempt >= MAX_ATTEMPTS) {
console.log(MAX_ATTEMPTS, 'attempts exceeded. Display error.');
displayErrorPage(res);
} else {
console.log('Retrying...');
attempt += 1;
setTimeout(redirect, 1500);
}
});
};
redirect();
};
const balanceUpgrade = (req, socket, upgradeHead, params) => {
const par = params || {};
assert((par instanceof Object), 'params must be an object or unspecified');
const { tags, port, address } = params;
const host = address || doProvider.getServer(tags);
if (!host) {
return socket.end('Something went wrong -- no host found');
}
req.target =
{
host,
tags,
port,
protocol: 'wss:',
};
return proxy.ws(req, socket, upgradeHead, {
target: req.target,
secure: true,
});
};
function getStats() {
return doProvider.getServerList();
}
function updateServers() {
return doProvider.updateServers();
}
return {
getStats,
balance,
balanceUpgrade,
updateServers,
};
};