the-shepherd
Version:
Control a herd of wild processes.
211 lines (204 loc) • 7.39 kB
JavaScript
// Generated by CoffeeScript 2.5.1
(function() {
var $, Groups, Health, Http, echo, quoted, verbose;
$ = require('bling');
Http = require('http');
({echo, verbose, quoted} = require('../common'));
({Groups} = require('../daemon/groups'));
$.extend(module.exports, Health = {
defaultInterval: 10000,
defaultTimeout: 3000,
monitor: function(group, path, exec, interval, status, text, timeout) {
var monitorKey;
if (exec != null) {
if (!(exec.length > 0)) {
return new Error(`Invalid exec command: ${exec}`);
}
} else if (path != null) {
if (!(path.length > 0)) {
return new Error(`Invalid path: ${path}`);
}
} else {
return new Error("Either path or exec is required.");
}
verbose("Health.monitor", path, exec, interval, status, text, timeout);
interval = parseInt(interval != null ? interval : Health.defaultInterval, 10);
if (!(isFinite(interval) && !isNaN(interval) && ((0 < interval && interval < 4294967295)))) {
return new Error(`Invalid interval: ${interval}.`);
}
if (status != null) {
status = parseInt(status, 10);
if (!(isFinite(status) && !isNaN(status) && ((0 < status && status < 1000)))) {
return new Error(`Invalid status: ${status}.`);
}
}
text = String(text != null ? text : '');
timeout = parseInt(timeout != null ? timeout : Health.defaultTimeout, 10);
if (!(isFinite(timeout) && !isNaN(timeout) && ((0 < timeout && timeout < 4294967295)))) {
return new Error(`Invalid timeout: ${timeout}.`);
}
monitorKey = path != null ? path : exec;
group.monitors || (group.monitors = Object.create(null));
if (monitorKey in group.monitors) {
return new Error("Group is already monitored.");
}
verbose("Adding health monitor", {path, interval, status, text, timeout});
group.monitors[monitorKey] = $.interval(interval, function() {
var i, len, proc, results;
results = [];
for (i = 0, len = group.length; i < len; i++) {
proc = group[i];
if (proc.expected) {
results.push((function(group, path, exec, interval, status, text, timeout, proc) {
var countdown, fail, req, res;
countdown = null;
if (proc.enabled && !proc.started) {
proc.healthy = false;
return;
}
proc.healthy = void 0;
fail = function(msg) {
var ref, ref1;
clearTimeout(countdown);
echo(`Health check failed (${msg}), pid: ${(ref = proc.proc) != null ? ref.pid : void 0} port: ${proc.port}`);
proc.healthy = false;
return (ref1 = proc.proc) != null ? ref1.kill() : void 0;
};
if (timeout > 0) {
countdown = setTimeout((() => {
return fail('timeout');
}), timeout);
}
if (exec != null) {
res = Shell.exec(exec, {
silent: true,
async: false
});
if ((status != null) && res.code !== status) {
return fail("bad status: " + res.code);
} else if ((text != null) && !(res.stdout.indexOf(text) > -1)) {
return fail("bad text: " + res.stdout);
} else {
return proc.healthy = true;
}
} else if (path != null) {
req = Http.get({
host: "127.0.0.1",
port: proc.port,
path: path
}, function(res) {
var buffer;
clearTimeout(countdown);
if (status !== 0 && res.statusCode !== status) {
return fail("bad status: " + res.statusCode);
}
if (text.length > 0) {
buffer = "";
res.setEncoding('utf8');
res.on('data', function(data) {
return buffer += data;
});
res.on('end', function() {
if (!(buffer.indexOf(text) > -1)) {
return fail("text not found: " + text);
}
});
}
res.on('error', function(err) {
return fail("response error: " + String(err));
});
return proc.healthy = true;
});
return req.on('error', function(err) {
return fail("request error: " + String(err));
});
}
})(group, path, exec, interval, status, text, timeout, proc));
}
}
return results;
});
Object.assign(group.monitors[monitorKey], {interval, status, text, timeout});
return true;
},
unmonitor: function(group, path) {
var check, ref;
if (!('monitors' in group)) {
return false;
}
if ((path != null) && !(path in group.monitors)) {
return false;
}
if (path != null) {
group.monitors[path].cancel();
} else {
ref = group.monitors;
for (path in ref) {
check = ref[path];
check.cancel();
delete group.monitors[path];
}
}
return true;
},
pause: function(group, path) {
var check, ref;
if (!('monitors' in group)) {
return false;
}
if ((path != null) && !(path in group.monitors)) {
return false;
}
if (path != null) {
group.monitors[path].pause();
group.monitors[path].paused = true;
} else {
ref = group.monitors;
for (path in ref) {
check = ref[path];
check.pause();
}
}
return true;
},
resume: function(group, path) {
var check, ref;
if (!('monitors' in group)) {
return false;
}
if ((path != null) && !(path in group.monitors)) {
return false;
}
if (path != null) {
group.monitors[path].resume();
group.monitors[path].paused = false;
} else {
ref = group.monitors;
for (path in ref) {
check = ref[path];
check.resume();
}
}
return true;
},
toConfig: function() {
var items;
items = [];
Groups.forEach(function(group) {
var interval, mon, path, paused, ref, results, status, text, timeout;
if (group.monitors == null) {
return;
}
ref = group.monitors;
results = [];
for (path in ref) {
mon = ref[path];
({interval, status, text, timeout, paused} = mon);
results.push(items.push(`health --group ${group.name} --path \"${path}\"` + (status > 0 ? ` --status ${status}` : "") + (interval > 0 ? ` --interval ${Math.floor(interval / 1000)}` : "") + (text.length > 0 ? ` --contains ${quoted(text)}` : "") + (timeout > 0 ? ` --timeout ${timeout}` : "") + (paused ? " --pause" : "")));
}
return results;
});
return items.join("\n");
}
});
}).call(this);