diff --git a/lib/provider.js b/lib/provider.js index c428b834..20dd6448 100644 --- a/lib/provider.js +++ b/lib/provider.js @@ -2,11 +2,11 @@ var path = require('path') var fork = require('child_process').fork var adb = require('adbkit') -var async = require('async') +var Q = require('q') var log = require('./util/logger').createLogger('provider') var client = adb.createClient() -var workers = {} +var workers = Object.create(null) client.trackDevices(function(err, tracker) { if (err) { @@ -96,30 +96,62 @@ function maybeDisconnect(device) { return false } -function gracefullyKillWorker(id, done) { - var proc = workers[id].proc - , timer - - timer = setTimeout(function() { - log.error('Device worker "%s" did not stop in time', id) - proc.removeListener('exit', onExit) - log.warn('Force killing worker of device "%s"', id) - proc.kill('SIGKILL') - done() - }, 10000) +function tryKillWorker(id) { + var deferred = Q.defer(), + worker = workers[id] function onExit() { - clearTimeout(timer) - done() + deferred.resolve() } - proc.once('exit', onExit) - proc.kill('SIGTERM') + worker.proc.once('exit', onExit) + worker.proc.kill('SIGTERM') + + return deferred.promise.finally(function() { + worker.proc.removeListener('exit', onExit) + }) +} + +function forceKillWorker(id) { + log.warn('Force killing worker of device "%s"', id) + + var deferred = Q.defer() + , worker = workers[id] + + function onExit() { + deferred.resolve() + } + + worker.proc.once('exit', onExit) + worker.proc.kill('SIGKILL') + + return deferred.promise.finally(function() { + worker.proc.removeListener('exit', onExit) + }) +} + +function gracefullyKillWorker(id) { + var deferred = Q.defer() + + tryKillWorker(id) + .timeout(10000) + .then(deferred.resolve) + .catch(function() { + log.error('Device worker "%s" did not stop in time', id) + forceKillWorker(id).then(deferred.resolve) + }) + + return deferred.promise } function gracefullyExit() { log.info('Stopping all workers') - async.each(Object.keys(workers), gracefullyKillWorker, function(err) { + Q.spawn(function* foo() { + var ops = [] + for (var id in workers) { + ops.push(gracefullyKillWorker(id)) + } + yield Q.all(ops) log.info('All cleaned up') process.exit(0) })