UNPKG

thread-pool

Version:

Simple thread pooling for Node.js.

174 lines (151 loc) 4.82 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = spawn; var _child_process = require('child_process'); var _child_process2 = _interopRequireDefault(_child_process); var _processBody = require('./process-body'); var _processBody2 = _interopRequireDefault(_processBody); var _symbols = require('./symbols'); var _symbols2 = _interopRequireDefault(_symbols); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Whenever this function is called, we should be confident that * there is at least 1 child process waiting to receive a task. * * This function will check to see if there is a task queued to be * performed and will call `assign` to hand it off to the waiting * child process. * * The `assign` method will return a promise so when that promise * resolves, we should pass the resolution on to the `resolve` * function created when the waiting task was assigned. Same with * errors. * * @param {Pool} pool An instance of a child process pool. * * @return {undefined} */ function checkTaskQueue(pool) { if (pool[_symbols2.default.TASK_QUEUE].length) { (function () { var task = pool[_symbols2.default.TASK_QUEUE].shift(); pool.assign(task.task).then(function (data) { return task.resolve(data); }).catch(function (data) { return task.catch(data); }); })(); } else { console.log('Thread Pool: 1 new idle thread. ' + pool[_symbols2.default.WAITING].length + '/' + pool[_symbols2.default.MAX_SIZE] + ' threads idle.'); } } /** * Procedure for when a process completes a task. * * @param {Pool} pool A thread pool instance. * @param {ChildProcess} child A thread. * @param {Object} msg The message that came through from the child. * * @return {undefined} */ function onComplete(pool, child, msg) { var resolver = child[_symbols2.default.RESOLVER]; /* * Clear any running timers. */ child[_symbols2.default.TIMER] && clearTimeout(child[_symbols2.default.TIMER]); /* * Reset the resolver and rejecter. */ child[_symbols2.default.RESOLVER] = null; child[_symbols2.default.REJECTER] = null; child[_symbols2.default.TIMER] = null; /* * Put the child process back into the waiting pool. */ pool[_symbols2.default.WAITING].push(child); /* * Check to see if there are other tasks that need to * be completed. */ checkTaskQueue(pool); /* * Resolve the promise with the data from the child process. */ resolver && resolver(msg.data); } /** * Give users the ability to receive and reply to messages from * child processes. * * @param {Pool} pool A thread pool instance. * @param {ChildProcess} child A thread. * @param {Object} msg The message that came through from the child. * * @return {undefined} */ function onMessage(pool, child, msg) { var reply = function reply(data) { return child.send({ type: 'reply', id: msg.id, data: data }); }; pool[_symbols2.default.HANDLER] && pool[_symbols2.default.HANDLER](msg.data, reply); } /** * Creates a new child process from the processBody string. * * @param {Pool} pool A thread pool instance. * * @return {ChildProcess} */ function spawn(pool) { /* * Create a child process. */ var child = _child_process2.default.fork(null, [], { execPath: 'node', execArgv: ['-e', _processBody2.default] }); /* * Add the process to the list of total processes. */ pool[_symbols2.default.PIDS].push(child); /* * Set up 2 new properties to help work with promises. */ child[_symbols2.default.RESOLVER] = null; child[_symbols2.default.REJECTER] = null; child[_symbols2.default.TIMER] = null; child[_symbols2.default.KILLSIGINT] = false; /* * When a child closes, fire a rejecter if we have one, * remove the child from our list of total pool processes, * and spawn a new child if we need it to resurrect. */ child.on('close', function (data) { child[_symbols2.default.REJECTER] && child[_symbols2.default.REJECTER](data); pool[_symbols2.default.PIDS].splice(pool[_symbols2.default.PIDS].indexOf(child), 1); !child[_symbols2.default.KILLSIGINT] && spawn(pool, 'resurrect'); }); /* * When the child process sends back a `done` message... */ child.on('message', function (msg) { switch (msg.type) { case 'done': return onComplete(pool, child, msg); case 'message': return onMessage(pool, child, msg); default: return; } }); /* * Put the child process into the waiting pool and check to * see if there are any tasks to be completed. */ pool[_symbols2.default.WAITING].push(child); checkTaskQueue(pool); return child; }