UNPKG

the-shepherd

Version:

Control a herd of wild processes.

419 lines (394 loc) 11.7 kB
// Generated by CoffeeScript 1.8.0 (function() { var $, Process, Shell, attach_ports, log, lsof_cmd, port, psCache, ps_cmd, ps_parse, signals; $ = require('bling'); Shell = require('shelljs'); Process = module.exports; log = $.logger("[Process]"); Process.exec = function(cmd, verbose) { var append_output, child, err, p, ret, _ref; try { return p = $.Promise(); } finally { try { if (verbose) { log("shell >", cmd); } ret = { output: "" }; child = Shell.exec(cmd, { silent: true, async: true }, function(exitCode) { var err, _ref; try { if (exitCode !== 0) { return p.reject(ret.output); } else { return p.resolve(ret.output); } } catch (_error) { err = _error; return log("exec: error handling process exit:", (_ref = err.stack) != null ? _ref : err); } }); child.stdout.on("data", append_output = function(data) { return ret.output += String(data); }); child.stderr.on("data", append_output); } catch (_error) { err = _error; log("exec: error in running process:", (_ref = err.stack) != null ? _ref : err); } } }; psCache = new $.Cache(2, 100); ps_cmd = "ps -eo uid,pid,ppid,pcpu,rss,command"; ps_parse = function(output) { var err, keys, _ref; try { output = output.split('\n').map(function(line) { return line.split(/[ ]+/).slice(1); }).slice(0, -1); keys = output[0].map($.slugize); return output.slice(1).map(function(row) { var e, i, key, ret, val, _i, _len; try { return ret = Object.create(null); } finally { for (i = _i = 0, _len = keys.length; _i < _len; i = ++_i) { key = keys[i]; if (i === keys.length - 1) { ret[key] = row.slice(i).join(' '); } else { val = row[i]; try { val = parseInt(val, 10); if (!isFinite(val)) { val = row[i]; } } catch (_error) { e = _error; val = row[i]; } finally { ret[key] = val; } } if (ret[key] == null) { log("ps_parse failed to parse line:", key, i, row[i], ret[key]); } } } }); } catch (_error) { err = _error; return log("ps_parse error:", (_ref = err.stack) != null ? _ref : err); } }; lsof_cmd = "lsof -Pni | grep LISTEN"; attach_ports = function(procs) { var attached, err, index, proc, _i, _len, _ref; try { return attached = $.Promise(); } finally { try { index = Object.create(null); for (_i = 0, _len = procs.length; _i < _len; _i++) { proc = procs[_i]; index[proc.pid] = proc; proc.ports = []; } Process.exec(lsof_cmd).then(function(output) { var err, line, pid, port, _j, _len1, _ref, _ref1; try { _ref = output.split(/\n/g); for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { line = _ref[_j]; line = line.split(/\s+/g); if (line.length < 8) { continue; } pid = parseInt(line[1], 10); port = parseInt(line[8].split(/:/)[1], 10); if (!(pid in index)) { index[pid] = { pid: pid, ports: [] }; } try { index[pid].ports.push(port); } catch (_error) { err = _error; log(err, pid, index[pid]); } } return attached.resolve(procs); } catch (_error) { err = _error; return log("attach_ports error while parsing output:", (_ref1 = err.stack) != null ? _ref1 : err); } }); } catch (_error) { err = _error; log("attach_ports error:", (_ref = err.stack) != null ? _ref : err); } } }; Process.clearCache = function() { psCache.del(ps_cmd); return Process; }; Process.find = function(query) { var err, p, _ref; try { return p = $.Promise(); } finally { try { query = (function() { switch ($.type(query)) { case "string": return { cmd: new RegExp(query) }; case "number": return { pid: query }; default: return query; } })(); if (psCache.has(ps_cmd)) { p.resolve(psCache.get(ps_cmd).filter(function(item) { return $.matches(query, item); })); } else { Process.exec(ps_cmd).then((function(output) { return attach_ports(ps_parse(output)).then((function(procs) { var err, _ref; try { return p.resolve(psCache.set(ps_cmd, procs).filter(function(item) { return $.matches(query, item); })); } catch (_error) { err = _error; return log("find error in results:", (_ref = err.stack) != null ? _ref : err); } }), p.reject); }), p.reject); } } catch (_error) { err = _error; log("find error:", (_ref = err.stack) != null ? _ref : err); } } }; Process.findOne = function(query) { var p; try { return p = $.Promise(); } finally { Process.find(query).then((function(out) { var err, _ref; try { return p.resolve(out[0]); } catch (_error) { err = _error; return log("findOne error:", (_ref = err.stack) != null ? _ref : err); } }), p.reject); } }; Process.findTree = function(query) { var p; try { return p = $.Promise(); } finally { Process.findOne(query).then(function(proc) { return Process.tree(proc).then(p.resolve, p.reject); }); } }; Process.signals = signals = { SIGHUP: 1, SIGINT: 2, SIGKILL: 9, SIGTERM: 15, HUP: 1, INT: 2, KILL: 9, TERM: 15 }; Process.getSignalNumber = function(signal) { var _ref; return (_ref = signals[signal]) != null ? _ref : ($.is('number', signal) ? signal : 15); }; Process.kill = function(pid, signal) { var err, _ref; try { return Process.exec("kill -" + (Process.getSignalNumber(signal)) + " " + pid); } catch (_error) { err = _error; return log("kill error:", (_ref = err.stack) != null ? _ref : err); } }; Process.tree = function(proc) { var p, q; try { return q = $.Promise(); } finally { p = $.Progress(1); if (proc) { Process.find({ ppid: proc.pid }).then((function(children) { var child, err, _i, _len, _ref; try { proc.children = children; for (_i = 0, _len = children.length; _i < _len; _i++) { child = children[_i]; p.include(Process.tree(child)); } return p.resolve(1, proc); } catch (_error) { err = _error; return log("tree error:", (_ref = err.stack) != null ? _ref : err); } }), q.reject); } p.then((function() { return q.resolve(proc); }), q.reject); } }; Process.walk = function(node, visit, depth) { var child, err, p, _i, _len, _ref, _ref1; if (depth == null) { depth = 0; } try { return p = $.Progress(1); } finally { try { p.include(visit(node, depth)); } catch (_error) { err = _error; log("walk error (in visit):", (_ref = err.stack) != null ? _ref : err); p.reject(err); } _ref1 = node.children; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { child = _ref1[_i]; p.include(Process.walk(child, visit, depth + 1)); } p.finish(1); } }; Process.killTree = function(proc, signal) { var err, fail, p, tokill; try { return p = $.Promise(); } finally { try { signal = Process.getSignalNumber(signal); proc = (function() { switch ($.type(proc)) { case 'string': case 'number': return { pid: proc }; default: return proc; } })(); tokill = []; fail = function(msg, err) { var _ref; log(msg, (_ref = err != null ? err.stack : void 0) != null ? _ref : err); return p.reject(err); }; Process.tree(proc).then((function(tree) { var err; try { Process.walk(tree, function(node) { if (node.pid) { return tokill.push(node.pid); } else { return fail("killTree invalid node (no pid):", node); } }); if (tokill.length) { return Process.exec("kill -" + signal + " " + (tokill.join(' ')) + " &> /dev/null").then(p.resolve, function(err) { return fail("killTree error while killing", err); }); } } catch (_error) { err = _error; return fail("killTree error while walking:", err); } }), p.reject); } catch (_error) { err = _error; fail("killTree error:", err); } } }; Process.summarize = function(proc) { var p; proc.rss = proc.cpu = 0; try { return p = $.Promise(); } finally { Process.tree(proc).then(function(tree) { Process.walk(tree, function(node, depth) { proc.rss += node.rss; return proc.cpu += node.cpu; }); return p.resolve(tree); }); } }; Process.printTree = function(proc, indent, spacer) { var child, err, ret, _i, _len, _ref, _ref1, _ref2; try { spacer || (spacer = " \\_"); indent || (indent = "* "); ret = indent + proc.pid + " " + proc.command; if ((_ref = proc.ports) != null ? _ref.length : void 0) { ret += " [:" + proc.ports.join(", :") + "]"; } ret += " {mem: " + ($.commaize(proc.rss)) + "kb cpu: " + proc.cpu + "%}\n"; indent = spacer + indent; _ref1 = proc.children; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { child = _ref1[_i]; ret += Process.printTree(child, indent, " "); } indent.replace(/^ /, ''); return ret; } catch (_error) { err = _error; return log("printTree error:", (_ref2 = err.stack) != null ? _ref2 : err); } }; if (require.main === module) { port = parseInt(process.argv[2], 10) || 8000; log("Tree for owner of:", port); Process.find({ ports: port }).then(function(procs) { var proc, _i, _len, _results; _results = []; for (_i = 0, _len = procs.length; _i < _len; _i++) { proc = procs[_i]; _results.push(Process.tree(proc).then(function(tree) { return console.log(Process.printTree(tree)); })); } return _results; }); } }).call(this);