UNPKG

multiprocessing

Version:
156 lines (138 loc) 4.83 kB
'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var fork = require('child_process').fork; var jsonUtils = require('./json-utils'); var allWorkers = []; process.on('exit', function () { return allWorkers.forEach(function (worker) { return worker.process.kill(); }); }); function makeError(errorMsg, stack) { var err = new Error(errorMsg); err.stack = stack; return err; } module.exports = function () { function WorkerWrapper() { _classCallCheck(this, WorkerWrapper); this.process = null; this.runningJobs = 0; this.terminated = false; this.registeredJobs = {}; this.fnOrModulePaths = {}; this.timeout = null; this.startWorkerProcess(); allWorkers.push(this); } _createClass(WorkerWrapper, [{ key: 'startWorkerProcess', value: function startWorkerProcess() { var _this = this; this.process = fork(__dirname + '/worker.js'); for (var regJobId in this.registeredJobs) { if (this.registeredJobs.hasOwnProperty(regJobId)) { var job = this.registeredJobs[regJobId]; this.registerJob(regJobId, job.fnOrModulePath, job.callback); } } this.process.on('message', function (data) { var job = _this.registeredJobs[data.jobId]; if (job.terminated) { return; } clearTimeout(_this.timeout); var err = null; if (data.error) { err = makeError(data.error, data.stack); } job.callback(err, data); if (data.jobDone) { _this.runningJobs -= 1; } else if (job.timeout > 0) { _this.startJobTimeout(job); } if (_this.terminated && _this.runningJobs === 0) { _this.process.disconnect(); } }); } }, { key: 'runJob', value: function runJob(jobId, index, argList) { if (this.terminated) { return; } // TODO: should this be an error? this.process.send({ jobId: jobId, index: index, argList: jsonUtils.safeStringify(argList) }); this.runningJobs += 1; var job = this.registeredJobs[jobId]; if (job.timeout > 0) { this.startJobTimeout(job); } } }, { key: 'registerJob', value: function registerJob(jobId, fnOrModulePath, options, callback) { var timeout = (options ? options.timeout : null) || -1; if (this.terminated) { return; } // TODO: should this be an error? this.registeredJobs[jobId] = { callback: callback, fnOrModulePath: fnOrModulePath, timeout: timeout, options: options }; var modulePath = typeof fnOrModulePath === 'string' ? fnOrModulePath : null; var fnStr = typeof fnOrModulePath === 'function' ? fnOrModulePath.toString() : null; this.process.send({ jobId: jobId, modulePath: modulePath, fnStr: fnStr }); } }, { key: 'deregisterJob', value: function deregisterJob(jobId) { if (this.terminated) { return; } // TODO: should this be an error? delete this.registeredJobs[jobId]; this.process.send({ jobId: jobId, deregisterJob: true }); } }, { key: 'terminateImmediately', value: function terminateImmediately() { this.terminated = true; this.process.disconnect(); for (var cbName in this.registeredJobs) { if (this.registeredJobs.hasOwnProperty(cbName)) { this.registeredJobs[cbName].callback(new Error('Pool was closed'), null); } } } }, { key: 'terminateAfterJobsComplete', value: function terminateAfterJobsComplete() { this.terminated = true; if (this.runningJobs === 0) { this.process.disconnect(); } } }, { key: 'startJobTimeout', value: function startJobTimeout(job) { var _this2 = this; this.timeout = setTimeout(function () { job.terminated = true; _this2.process.kill(); _this2.startWorkerProcess(); job.callback(new Error('Task timed out'), null); }, job.timeout); } }]); return WorkerWrapper; }();