UNPKG

chimpy

Version:

Develop acceptance tests & end-to-end tests with realtime feedback.

102 lines (90 loc) 3.24 kB
"use strict"; var cp = require('child_process'), log = require('./log'); module.exports = { start: function start(options, callback) { var child = this.spawn(options); if (options.waitForMessage) { this.waitForMessage(options, child, callback); } else { callback(); } return child; }, spawn: function spawn(options) { log.debug('[chimp][' + options.prefix + ']', 'starting process'); var child = cp.spawn(options.bin, options.args); this.logOutputs(options.prefix, child); return child; }, logOutputs: function logOutputs(prefix, child) { child.stdout.on('data', function (data) { log.debug('[chimp][' + prefix + '.stdout]', data.toString()); }); child.stderr.on('data', function (data) { log.debug('[chimp][' + prefix + '.stderr]', data.toString()); }); }, waitForMessage: function waitForMessage(options, child, callback) { child.stderr.on('data', onDataStdErr); child.stdout.on('data', onDataStdOut); function onDataStdErr(data) { onData(data, function () { child.stderr.removeListener('data', onDataStdErr); }); } function onDataStdOut(data) { onData(data, function () { child.stdout.removeListener('data', onDataStdOut); }); } function onData(data, removeListener) { if (data.toString().match(options.waitForMessage)) { removeListener(); log.debug('[chimp][' + options.prefix + ']', 'started successfully'); return callback(); } if (data.toString().match(options.errorMessage)) { log.error('[chimp][' + options.prefix + ']', 'failed to start'); log.error(data.toString()); callback(data.toString()); } } }, kill: function kill(options, callback) { log.debug('[chimp][' + options.prefix + ']', 'kill called on ' + options.prefix + ' process with pid', options.child.pid); options.signal = options.signal || 'SIGTERM'; try { log.debug('[chimp][' + options.prefix + ']', 'checking if process exists'); process.kill(options.child.pid, 0); log.debug('[chimp][' + options.prefix + ']', options.prefix + ' process exists, killing it with', options.signal); process.kill(options.child.pid, options.signal); } catch (e) { log.debug('[chimp][' + options.prefix + ']', options.prefix + ' process does not exists, ignoring'); options.child = null; return callback(); } var delay = 300, totalRetries = 10, retries = totalRetries * (1000 / delay), attempt = 0; var waitForProcessToDie = setInterval(function () { try { if (retries-- < 0) { throw new Error('Process took too long to die'); } log.debug('[chimp][' + options.prefix + ']', 'waiting for process to die (' + attempt++ + '/' + totalRetries + ')'); process.kill(options.child.pid, 0); } catch (e) { clearInterval(waitForProcessToDie); if (e.code === 'ESRCH') { log.debug('[chimp][' + options.prefix + ']', 'process is dead'); options.child = null; callback(); } else { callback(e); } } }, delay); } };