workerpool
Advanced tools
Comparing version 3.0.0 to 3.1.0
@@ -68,4 +68,24 @@ /******/ (function(modules) { // webpackBootstrap | ||
// node.js | ||
worker.on = process.on.bind(process); | ||
worker.send = process.send.bind(process); | ||
var WorkerThreads; | ||
try { | ||
WorkerThreads = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module \"worker_threads\""); e.code = 'MODULE_NOT_FOUND'; throw e; }())); | ||
} catch(error) { | ||
if (typeof error === 'object' && error !== null && error.code == 'MODULE_NOT_FOUND') { | ||
// no worker_threads, fallback to sub-process based workers | ||
} else { | ||
throw error; | ||
} | ||
} | ||
if (WorkerThreads && | ||
/* if there is a parentPort, we are in a WorkerThread */ | ||
WorkerThreads.parentPort !== null) { | ||
var parentPort = WorkerThreads.parentPort; | ||
worker.send = parentPort.postMessage.bind(parentPort); | ||
worker.on = parentPort.on.bind(parentPort); | ||
} else { | ||
worker.on = process.on.bind(process); | ||
worker.send = process.send.bind(process); | ||
} | ||
} | ||
@@ -72,0 +92,0 @@ else { |
@@ -7,4 +7,4 @@ /** | ||
* | ||
* @version 3.0.0 | ||
* @date 2018-12-11 | ||
* @version 3.1.0 | ||
* @date 2019-02-17 | ||
* | ||
@@ -29,10 +29,10 @@ * @license | ||
if(typeof exports === 'object' && typeof module === 'object') | ||
module.exports = factory(require("os"), require("child_process")); | ||
module.exports = factory(require("os"), (function webpackLoadOptionalExternalModule() { try { return require("worker_threads"); } catch(e) {} }()), require("child_process")); | ||
else if(typeof define === 'function' && define.amd) | ||
define(["os", "child_process"], factory); | ||
define(["os", "worker_threads", "child_process"], factory); | ||
else if(typeof exports === 'object') | ||
exports["workerpool"] = factory(require("os"), require("child_process")); | ||
exports["workerpool"] = factory(require("os"), (function webpackLoadOptionalExternalModule() { try { return require("worker_threads"); } catch(e) {} }()), require("child_process")); | ||
else | ||
root["workerpool"] = factory(root["os"], root["child_process"]); | ||
})(this, function(__WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_8__) { | ||
root["workerpool"] = factory(root["os"], root["worker_threads"], root["child_process"]); | ||
})(this, function(__WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_11__, __WEBPACK_EXTERNAL_MODULE_12__) { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
@@ -102,3 +102,3 @@ /******/ // The module cache | ||
exports.worker = function worker(methods) { | ||
var worker = __webpack_require__(9); | ||
var worker = __webpack_require__(10); | ||
worker.add(methods); | ||
@@ -170,2 +170,3 @@ }; | ||
this.debugPortStart = options.debugPortStart || 43210; | ||
this.nodeWorker = options.nodeWorker; | ||
@@ -191,4 +192,12 @@ // configuration | ||
} | ||
this._boundNext = this._next.bind(this); | ||
if (this.nodeWorker === 'thread') { | ||
WorkerHandler.ensureWorkerThreads(); | ||
} | ||
} | ||
/** | ||
@@ -334,5 +343,3 @@ * Execute a function on a worker. | ||
var promise = worker.exec(task.method, task.params, task.resolver) | ||
.then(function () { | ||
me._next(); // trigger next task in the queue | ||
}) | ||
.then(me._boundNext) | ||
.catch(function () { | ||
@@ -371,5 +378,6 @@ // if the worker crashed and terminated, remove it from the pool | ||
// find a non-busy worker | ||
for (var i = 0, ii = this.workers.length; i < ii; i++) { | ||
var worker = this.workers[i]; | ||
if (!worker.busy()) { | ||
var workers = this.workers; | ||
for (var i = 0; i < workers.length; i++) { | ||
var worker = workers[i]; | ||
if (worker.busy() === false) { | ||
return worker; | ||
@@ -379,3 +387,3 @@ } | ||
if (this.workers.length < this.maxWorkers) { | ||
if (workers.length < this.maxWorkers) { | ||
// create a new worker | ||
@@ -385,5 +393,6 @@ worker = new WorkerHandler(this.script, { | ||
forkOpts: this.forkOpts, | ||
debugPort: this.debugPortStart + this.workers.length | ||
debugPort: this.debugPortStart + workers.length, | ||
nodeWorker: this.nodeWorker | ||
}); | ||
this.workers.push(worker); | ||
workers.push(worker); | ||
return worker; | ||
@@ -613,5 +622,3 @@ } | ||
_resolve = _reject = function () { | ||
throw new Error('Promise is already resolved'); | ||
}; | ||
_resolve = _reject = function () { }; | ||
@@ -640,5 +647,3 @@ return me; | ||
_resolve = _reject = function () { | ||
throw new Error('Promise is already resolved'); | ||
}; | ||
_resolve = _reject = function () { } | ||
@@ -829,2 +834,4 @@ return me; | ||
'use strict'; | ||
var Promise = __webpack_require__(4); | ||
@@ -836,2 +843,24 @@ var assign = __webpack_require__(6); | ||
function ensureWorkerThreads() { | ||
var WorkerThreads = tryRequire('worker_threads') | ||
if (!WorkerThreads) { | ||
throw new Error('WorkerPool: nodeWorkers = thread is not supported, Node >= 11.7.0 required') | ||
} | ||
return WorkerThreads; | ||
} | ||
function tryRequire(moduleName) { | ||
try { | ||
return __webpack_require__(7)(moduleName); | ||
} catch(error) { | ||
if (typeof error === 'object' && error !== null && error.code == 'MODULE_NOT_FOUND') { | ||
return null; | ||
// no worker_threads, fallback to sub-process based workers | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
// get the default worker script | ||
@@ -849,3 +878,3 @@ function getDefaultWorker() { | ||
// use embedded worker.js | ||
var blob = new Blob([__webpack_require__(7)], {type: 'text/javascript'}); | ||
var blob = new Blob([__webpack_require__(8)], {type: 'text/javascript'}); | ||
return window.URL.createObjectURL(blob); | ||
@@ -859,2 +888,48 @@ } | ||
function setupBrowserWorker(script, Worker) { | ||
// create the web worker | ||
var worker = new Worker(script); | ||
// add node.js API to the web worker | ||
worker.on = function (event, callback) { | ||
this.addEventListener(event, function (message) { | ||
callback(message.data); | ||
}); | ||
}; | ||
worker.send = function (message) { | ||
this.postMessage(message); | ||
}; | ||
return worker; | ||
} | ||
function setupWorkerThreadWorker(script, WorkerThreads) { | ||
var worker = new WorkerThreads.Worker(script, { | ||
stdout: false, // automatically pipe worker.STDOUT to process.STDOUT | ||
stderr: false // automatically pipe worker.STDERR to process.STDERR | ||
}); | ||
// make the worker mimic a child_process | ||
worker.send = function(message) { | ||
this.postMessage(message); | ||
}; | ||
worker.kill = function() { | ||
this.terminate(); | ||
}; | ||
worker.disconnect = function() { | ||
this.terminate(); | ||
}; | ||
return worker; | ||
} | ||
function setupProcessWorker(script, options, child_process) { | ||
// no WorkerThreads, fallback to sub-process based workers | ||
return child_process.fork( | ||
script, | ||
options.forkArgs, | ||
options.forkOpts | ||
); | ||
} | ||
// add debug flags to child processes if the node inspector is active | ||
@@ -881,3 +956,3 @@ function resolveForkOptions(opts) { | ||
execArgv: (opts.forkOpts && opts.forkOpts.execArgv || []) | ||
.concat(execArgv) | ||
.concat(execArgv) | ||
}) | ||
@@ -910,7 +985,6 @@ }); | ||
*/ | ||
function WorkerHandler(script, options) { | ||
function WorkerHandler(script, _options) { | ||
this.script = script || getDefaultWorker(); | ||
var options = _options || {}; | ||
var forkOptions; | ||
if (environment.platform == 'browser') { | ||
@@ -920,29 +994,22 @@ // check whether Worker is supported by the browser | ||
if (typeof Worker !== 'function' && (typeof Worker !== 'object' || typeof Worker.prototype.constructor !== 'function')) { | ||
throw new Error('Web workers not supported by the browser'); | ||
throw new Error('WorkerPool: Web workers not supported by the browser'); | ||
} | ||
// create the web worker | ||
this.worker = new Worker(this.script); | ||
this.worker = setupBrowserWorker(this.script, Worker); | ||
} else { | ||
// add node.js API to the web worker | ||
this.worker.on = function (event, callback) { | ||
this.addEventListener(event, function (message) { | ||
callback(message.data); | ||
}); | ||
}; | ||
this.worker.send = function (message) { | ||
this.postMessage(message); | ||
}; | ||
if (options.nodeWorker === 'thread') { | ||
var WorkerThreads = ensureWorkerThreads(); | ||
this.worker = setupWorkerThreadWorker(this.script, WorkerThreads); | ||
} else if (options.nodeWorker === 'auto') { | ||
if (WorkerThreads) { | ||
this.worker = setupWorkerThreadWorker(this.script, WorkerThreads); | ||
} else { | ||
this.worker = setupProcessWorker(this.script, resolveForkOptions(options), __webpack_require__(12)); | ||
} | ||
} else { | ||
this.worker = setupProcessWorker(this.script, resolveForkOptions(options), __webpack_require__(12)); | ||
} | ||
} | ||
else { | ||
// on node.js, create a child process | ||
forkOptions = resolveForkOptions(options); | ||
this.worker = __webpack_require__(8).fork( | ||
this.script, | ||
forkOptions.forkArgs, | ||
forkOptions.forkOpts | ||
); | ||
} | ||
var me = this; | ||
@@ -965,3 +1032,3 @@ | ||
var task = me.processing[id]; | ||
if (task) { | ||
if (task !== undefined) { | ||
// remove the task from the queue | ||
@@ -971,3 +1038,3 @@ delete me.processing[id]; | ||
// test if we need to terminate | ||
if (me.terminating) { | ||
if (me.terminating === true) { | ||
// complete worker termination if all tasks are finished | ||
@@ -997,7 +1064,7 @@ me.terminate(); | ||
for (var id in me.processing) { | ||
if (me.processing.hasOwnProperty(id)) { | ||
if (me.processing[id] !== undefined) { | ||
me.processing[id].resolver.reject(error); | ||
} | ||
} | ||
me.processing = {}; | ||
me.processing = Object.create(null); | ||
} | ||
@@ -1019,3 +1086,3 @@ | ||
this.processing = {}; // queue with tasks currently in progress | ||
this.processing = Object.create(null); // queue with tasks currently in progress | ||
@@ -1076,12 +1143,14 @@ this.terminating = false; | ||
resolver.promise | ||
.catch(function (error) { | ||
if (error instanceof Promise.CancellationError || error instanceof Promise.TimeoutError) { | ||
// remove this task from the queue. It is already rejected (hence this | ||
// catch event), and else it will be rejected again when terminating | ||
delete me.processing[id]; | ||
.catch(function (error) { | ||
if (error instanceof Promise.CancellationError || error instanceof Promise.TimeoutError) { | ||
// remove this task from the queue. It is already rejected (hence this | ||
// catch event), and else it will be rejected again when terminating | ||
delete me.processing[id]; | ||
// terminate worker | ||
me.terminate(true); | ||
} | ||
}); | ||
// terminate worker | ||
me.terminate(true); | ||
} else { | ||
throw error; | ||
} | ||
}); | ||
@@ -1111,7 +1180,7 @@ return resolver.promise; | ||
for (var id in this.processing) { | ||
if (this.processing.hasOwnProperty(id)) { | ||
if (this.processing[id] !== undefined) { | ||
this.processing[id].resolver.reject(new Error('Worker terminated')); | ||
} | ||
} | ||
this.processing = {}; | ||
this.processing = Object.create(null); | ||
} | ||
@@ -1170,2 +1239,7 @@ | ||
module.exports = WorkerHandler; | ||
module.exports._tryRequire = tryRequire; | ||
module.exports._setupProcessWorker = setupProcessWorker; | ||
module.exports._setupBrowserWorker = setupBrowserWorker; | ||
module.exports._setupWorkerThreadWorker = setupWorkerThreadWorker; | ||
module.exports.ensureWorkerThreads = ensureWorkerThreads; | ||
@@ -1271,2 +1345,36 @@ | ||
/* 7 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
var map = { | ||
"./Pool": 3, | ||
"./Pool.js": 3, | ||
"./Promise": 4, | ||
"./Promise.js": 4, | ||
"./WorkerHandler": 5, | ||
"./WorkerHandler.js": 5, | ||
"./environment": 1, | ||
"./environment.js": 1, | ||
"./generated/embeddedWorker": 8, | ||
"./generated/embeddedWorker.js": 8, | ||
"./header": 9, | ||
"./header.js": 9, | ||
"./worker": 10, | ||
"./worker.js": 10 | ||
}; | ||
function webpackContext(req) { | ||
return __webpack_require__(webpackContextResolve(req)); | ||
}; | ||
function webpackContextResolve(req) { | ||
return map[req] || (function() { throw new Error("Cannot find module '" + req + "'.") }()); | ||
}; | ||
webpackContext.keys = function webpackContextKeys() { | ||
return Object.keys(map); | ||
}; | ||
webpackContext.resolve = webpackContextResolve; | ||
module.exports = webpackContext; | ||
webpackContext.id = 7; | ||
/***/ }), | ||
/* 8 */ | ||
/***/ (function(module, exports) { | ||
@@ -1279,13 +1387,37 @@ | ||
*/ | ||
module.exports = "!function(r){function e(n){if(o[n])return o[n].exports;var t=o[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,e),t.loaded=!0,t.exports}var o={};e.m=r,e.c=o,e.p=\"\",e(0)}([function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,o){return Object.defineProperty(e,o,{value:r[o],enumerable:!0})},{})}function isPromise(r){return r&&\"function\"==typeof r.then&&\"function\"==typeof r.catch}var worker={};if(\"undefined\"!=typeof self&&\"function\"==typeof postMessage&&\"function\"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if(\"undefined\"==typeof process)throw new Error(\"Script must be executed as a worker\");worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval(\"(\"+fn+\")\");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on(\"message\",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error('Unknown method \"'+r.method+'\"');var o=e.apply(e,r.params);isPromise(o)?o.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:o,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send(\"ready\")},exports.add=worker.register}]);"; | ||
module.exports = "!function(r){function e(n){if(o[n])return o[n].exports;var t=o[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,e),t.loaded=!0,t.exports}var o={};e.m=r,e.c=o,e.p=\"\",e(0)}([function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,o){return Object.defineProperty(e,o,{value:r[o],enumerable:!0})},{})}function isPromise(r){return r&&\"function\"==typeof r.then&&\"function\"==typeof r.catch}var worker={};if(\"undefined\"!=typeof self&&\"function\"==typeof postMessage&&\"function\"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if(\"undefined\"==typeof process)throw new Error(\"Script must be executed as a worker\");var WorkerThreads;try{WorkerThreads=__webpack_require__(!function(){var r=new Error('Cannot find module \"worker_threads\"');throw r.code=\"MODULE_NOT_FOUND\",r}())}catch(r){if(\"object\"!=typeof r||null===r||\"MODULE_NOT_FOUND\"!=r.code)throw r}if(WorkerThreads&&null!==WorkerThreads.parentPort){var parentPort=WorkerThreads.parentPort;worker.send=parentPort.postMessage.bind(parentPort),worker.on=parentPort.on.bind(parentPort)}else worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval(\"(\"+fn+\")\");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on(\"message\",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error('Unknown method \"'+r.method+'\"');var o=e.apply(e,r.params);isPromise(o)?o.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:o,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send(\"ready\")},exports.add=worker.register}]);"; | ||
/***/ }), | ||
/* 8 */ | ||
/* 9 */ | ||
/***/ (function(module, exports) { | ||
module.exports = require("child_process"); | ||
/** | ||
* workerpool.js | ||
* https://github.com/josdejong/workerpool | ||
* | ||
* Offload tasks to a pool of workers on node.js and in the browser. | ||
* | ||
* @version @@version | ||
* @date @@date | ||
* | ||
* @license | ||
* Copyright (C) 2014-2016 Jos de Jong <wjosdejong@gmail.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy | ||
* of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
/***/ }), | ||
/* 9 */ | ||
/* 10 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
@@ -1314,4 +1446,24 @@ | ||
// node.js | ||
worker.on = process.on.bind(process); | ||
worker.send = process.send.bind(process); | ||
var WorkerThreads; | ||
try { | ||
WorkerThreads = __webpack_require__(11); | ||
} catch(error) { | ||
if (typeof error === 'object' && error !== null && error.code == 'MODULE_NOT_FOUND') { | ||
// no worker_threads, fallback to sub-process based workers | ||
} else { | ||
throw error; | ||
} | ||
} | ||
if (WorkerThreads && | ||
/* if there is a parentPort, we are in a WorkerThread */ | ||
WorkerThreads.parentPort !== null) { | ||
var parentPort = WorkerThreads.parentPort; | ||
worker.send = parentPort.postMessage.bind(parentPort); | ||
worker.on = parentPort.on.bind(parentPort); | ||
} else { | ||
worker.on = process.on.bind(process); | ||
worker.send = process.send.bind(process); | ||
} | ||
} | ||
@@ -1434,2 +1586,14 @@ else { | ||
/***/ }), | ||
/* 11 */ | ||
/***/ (function(module, exports) { | ||
module.exports = require("worker_threads"); | ||
/***/ }), | ||
/* 12 */ | ||
/***/ (function(module, exports) { | ||
module.exports = require("child_process"); | ||
/***/ }) | ||
@@ -1436,0 +1600,0 @@ /******/ ]) |
@@ -7,4 +7,4 @@ /** | ||
* | ||
* @version 3.0.0 | ||
* @date 2018-12-11 | ||
* @version 3.1.0 | ||
* @date 2019-02-17 | ||
* | ||
@@ -26,3 +26,3 @@ * @license | ||
*/ | ||
!function(r,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("os"),require("child_process")):"function"==typeof define&&define.amd?define(["os","child_process"],e):"object"==typeof exports?exports.workerpool=e(require("os"),require("child_process")):r.workerpool=e(r.os,r.child_process)}(this,function(__WEBPACK_EXTERNAL_MODULE_2__,__WEBPACK_EXTERNAL_MODULE_8__){return function(r){function e(o){if(t[o])return t[o].exports;var n=t[o]={exports:{},id:o,loaded:!1};return r[o].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var t={};return e.m=r,e.c=t,e.p="",e(0)}([function(r,e,t){var o=t(1);e.pool=function(r,e){return new(t(3))(r,e)},e.worker=function(r){t(9).add(r)},e.Promise=t(4),e.platform=o.platform,e.isMainThread=o.isMainThread,e.cpus=o.cpus},function(r,e,t){r.exports.platform="undefined"!=typeof Window||"undefined"!=typeof WorkerGlobalScope?"browser":"node",r.exports.isMainThread="browser"===r.exports.platform?"undefined"!=typeof Window:!process.connected,r.exports.cpus="browser"===r.exports.platform?self.navigator.hardwareConcurrency:t(2).cpus().length},function(r,e){r.exports=require("os")},function(r,e,t){function o(r,e){"string"==typeof r?this.script=r||null:(this.script=null,e=r),this.workers=[],this.tasks=[],e=e||{},this.forkArgs=e.forkArgs||[],this.forkOpts=e.forkOpts||{},this.debugPortStart=e.debugPortStart||43210,e&&"maxWorkers"in e?(n(e.maxWorkers),this.maxWorkers=e.maxWorkers):this.maxWorkers=Math.max((f.cpus||4)-1,1),e&&"minWorkers"in e&&("max"===e.minWorkers?this.minWorkers=Math.max((f.cpus||4)-1,1):(i(e.minWorkers),this.minWorkers=e.minWorkers,this.maxWorkers=Math.max(this.minWorkers,this.maxWorkers)),this._ensureMinWorkers())}function n(r){if(!s(r)||!c(r)||r<1)throw new TypeError("Option maxWorkers must be an integer number >= 1")}function i(r){if(!s(r)||!c(r)||r<0)throw new TypeError("Option minWorkers must be an integer number >= 0")}function s(r){return"number"==typeof r}function c(r){return Math.round(r)==r}var u=t(4),a=t(5),f=t(1);o.prototype.exec=function(r,e){if(e&&!Array.isArray(e))throw new TypeError('Array expected as argument "params"');if("string"==typeof r){var t=u.defer(),o=this.tasks,n={method:r,params:e,resolver:t,timeout:null};o.push(n);var i=t.promise.timeout;return t.promise.timeout=function(r){return-1!==o.indexOf(n)?(n.timeout=r,t.promise):i.call(t.promise,r)},this._next(),t.promise}if("function"==typeof r)return this.exec("run",[String(r),e]);throw new TypeError('Function or string expected as argument "method"')},o.prototype.proxy=function(){if(arguments.length>0)throw new Error("No arguments expected");var r=this;return this.exec("methods").then(function(e){var t={};return e.forEach(function(e){t[e]=function(){return r.exec(e,Array.prototype.slice.call(arguments))}}),t})},o.prototype._next=function(){if(this.tasks.length>0){var r=this._getWorker();if(r){var e=this,t=this.tasks.shift();if(t.resolver.promise.pending){var o=r.exec(t.method,t.params,t.resolver).then(function(){e._next()}).catch(function(){r.terminated&&(e._removeWorker(r),e._ensureMinWorkers()),e._next()});"number"==typeof t.timeout&&o.timeout(t.timeout)}else e._next()}}},o.prototype._getWorker=function(){for(var r=0,e=this.workers.length;r<e;r++){var t=this.workers[r];if(!t.busy())return t}return this.workers.length<this.maxWorkers?(t=new a(this.script,{forkArgs:this.forkArgs,forkOpts:this.forkOpts,debugPort:this.debugPortStart+this.workers.length}),this.workers.push(t),t):null},o.prototype._removeWorker=function(r){r.terminate(),this._removeWorkerFromList(r)},o.prototype._removeWorkerFromList=function(r){var e=this.workers.indexOf(r);-1!=e&&this.workers.splice(e,1)},o.prototype.terminate=function(r,e){var t=function(r){this._removeWorkerFromList(r)},o=t.bind(this),n=[];return this.workers.slice().forEach(function(t){var i=t.terminateAndNotify(r,e).then(o);n.push(i)}),u.all(n)},o.prototype.clear=function(r){this.terminate(r)},o.prototype.stats=function(){var r=this.workers.length,e=this.workers.filter(function(r){return r.busy()}).length;return{totalWorkers:r,busyWorkers:e,idleWorkers:r-e,pendingTasks:this.tasks.length,activeTasks:e}},o.prototype._ensureMinWorkers=function(){if(this.minWorkers)for(var r=this.workers.length;r<this.minWorkers;r++)this.workers.push(new a(this.script,{forkArgs:this.forkArgs,forkOpts:this.forkOpts,debugPort:this.debugPortStart+r}))},r.exports=o},function(r,e){"use strict";function t(r,e){var s=this;if(!(this instanceof t))throw new SyntaxError("Constructor must be called with the new operator");if("function"!=typeof r)throw new SyntaxError("Function parameter handler(resolve, reject) missing");var c=[],u=[];this.resolved=!1,this.rejected=!1,this.pending=!0;var a=function(r,e){c.push(r),u.push(e)};this.then=function(r,e){return new t(function(t,n){var i=r?o(r,t,n):t,s=e?o(e,t,n):n;a(i,s)},s)};var f=function(r){return s.resolved=!0,s.rejected=!1,s.pending=!1,c.forEach(function(e){e(r)}),a=function(e,t){e(r)},f=p=function(){throw new Error("Promise is already resolved")},s},p=function(r){return s.resolved=!1,s.rejected=!0,s.pending=!1,u.forEach(function(e){e(r)}),a=function(e,t){t(r)},f=p=function(){throw new Error("Promise is already resolved")},s};this.cancel=function(){return e?e.cancel():p(new n),s},this.timeout=function(r){if(e)e.timeout(r);else{var t=setTimeout(function(){p(new i("Promise timed out after "+r+" ms"))},r);s.always(function(){clearTimeout(t)})}return s},r(function(r){f(r)},function(r){p(r)})}function o(r,e,t){return function(o){try{var n=r(o);n&&"function"==typeof n.then&&"function"==typeof n.catch?n.then(e,t):e(n)}catch(r){t(r)}}}function n(r){this.message=r||"promise cancelled",this.stack=(new Error).stack}function i(r){this.message=r||"timeout exceeded",this.stack=(new Error).stack}t.prototype.catch=function(r){return this.then(null,r)},t.prototype.always=function(r){return this.then(r,r)},t.all=function(r){return new t(function(e,t){var o=r.length,n=[];o?r.forEach(function(r,i){r.then(function(r){n[i]=r,0==--o&&e(n)},function(r){o=0,t(r)})}):e(n)})},t.defer=function(){var r={};return r.promise=new t(function(e,t){r.resolve=e,r.reject=t}),r},n.prototype=new Error,n.prototype.constructor=Error,n.prototype.name="CancellationError",t.CancellationError=n,i.prototype=new Error,i.prototype.constructor=Error,i.prototype.name="TimeoutError",t.TimeoutError=i,r.exports=t},function(r,e,t){function o(){if("browser"==a.platform){if("undefined"==typeof Blob)throw new Error("Blob not supported by the browser");if(!window.URL||"function"!=typeof window.URL.createObjectURL)throw new Error("URL.createObjectURL not supported by the browser");var r=new Blob([t(7)],{type:"text/javascript"});return window.URL.createObjectURL(r)}return __dirname+"/worker.js"}function n(r){r=r||{};var e=process.execArgv.join(" "),t=-1!==e.indexOf("--inspect"),o=-1!==e.indexOf("--debug-brk"),n=[];return t&&(n.push("--inspect="+r.debugPort),o&&n.push("--debug-brk")),u({},r,{forkArgs:r.forkArgs,forkOpts:u({},r.forkOpts,{execArgv:(r.forkOpts&&r.forkOpts.execArgv||[]).concat(n)})})}function i(r){for(var e=new Error(""),t=Object.keys(r),o=0;o<t.length;o++)e[t[o]]=r[t[o]];return e}function s(r,e){function s(r){f.terminated=!0,f.terminating&&f.terminationHandler&&f.terminationHandler(f),f.terminating=!1;for(var e in f.processing)f.processing.hasOwnProperty(e)&&f.processing[e].resolver.reject(r);f.processing={}}function c(){f.requestQueue.forEach(f.worker.send.bind(f.worker)),f.requestQueue=[]}this.script=r||o();var u;if("browser"==a.platform){if("function"!=typeof Worker&&("object"!=typeof Worker||"function"!=typeof Worker.prototype.constructor))throw new Error("Web workers not supported by the browser");this.worker=new Worker(this.script),this.worker.on=function(r,e){this.addEventListener(r,function(r){e(r.data)})},this.worker.send=function(r){this.postMessage(r)}}else u=n(e),this.worker=t(8).fork(this.script,u.forkArgs,u.forkOpts);var f=this;r||(this.worker.ready=!0),this.requestQueue=[],this.worker.on("message",function(r){if("string"==typeof r&&"ready"===r)f.worker.ready=!0,c();else{var e=r.id,t=f.processing[e];t&&(delete f.processing[e],f.terminating&&f.terminate(),r.error?t.resolver.reject(i(r.error)):t.resolver.resolve(r.result))}}),this.worker.on("error",s),this.worker.on("exit",function(){s(new Error("Worker terminated unexpectedly"))}),this.processing={},this.terminating=!1,this.terminated=!1,this.terminationHandler=null,this.lastId=0}var c=t(4),u=t(6),a=t(1);s.prototype.methods=function(){return this.exec("methods")},s.prototype.exec=function(r,e,t){t||(t=c.defer());var o=++this.lastId;this.processing[o]={id:o,resolver:t};var n={id:o,method:r,params:e};this.terminated?t.reject(new Error("Worker is terminated")):this.worker.ready?this.worker.send(n):this.requestQueue.push(n);var i=this;return t.promise.catch(function(r){(r instanceof c.CancellationError||r instanceof c.TimeoutError)&&(delete i.processing[o],i.terminate(!0))}),t.promise},s.prototype.busy=function(){return Object.keys(this.processing).length>0},s.prototype.terminate=function(r,e){if(r){for(var t in this.processing)this.processing.hasOwnProperty(t)&&this.processing[t].resolver.reject(new Error("Worker terminated"));this.processing={}}if("function"==typeof e&&(this.terminationHandler=e),this.busy())this.terminating=!0;else{if(this.worker){if("function"==typeof this.worker.kill)this.worker.kill();else{if("function"!=typeof this.worker.terminate)throw new Error("Failed to terminate worker");this.worker.terminate()}this.worker=null}this.terminating=!1,this.terminated=!0,this.terminationHandler&&this.terminationHandler(this)}},s.prototype.terminateAndNotify=function(r,e){var t=c.defer();return e&&(t.promise.timeout=e),this.terminate(r,function(r){t.resolve(r)}),t.promise},r.exports=s},function(r,e){/* | ||
!function(r,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("os"),function(){try{return require("worker_threads")}catch(r){}}(),require("child_process")):"function"==typeof define&&define.amd?define(["os","worker_threads","child_process"],e):"object"==typeof exports?exports.workerpool=e(require("os"),function(){try{return require("worker_threads")}catch(r){}}(),require("child_process")):r.workerpool=e(r.os,r.worker_threads,r.child_process)}(this,function(__WEBPACK_EXTERNAL_MODULE_2__,__WEBPACK_EXTERNAL_MODULE_11__,__WEBPACK_EXTERNAL_MODULE_12__){return function(r){function e(o){if(t[o])return t[o].exports;var n=t[o]={exports:{},id:o,loaded:!1};return r[o].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var t={};return e.m=r,e.c=t,e.p="",e(0)}([function(r,e,t){var o=t(1);e.pool=function(r,e){return new(t(3))(r,e)},e.worker=function(r){t(10).add(r)},e.Promise=t(4),e.platform=o.platform,e.isMainThread=o.isMainThread,e.cpus=o.cpus},function(r,e,t){r.exports.platform="undefined"!=typeof Window||"undefined"!=typeof WorkerGlobalScope?"browser":"node",r.exports.isMainThread="browser"===r.exports.platform?"undefined"!=typeof Window:!process.connected,r.exports.cpus="browser"===r.exports.platform?self.navigator.hardwareConcurrency:t(2).cpus().length},function(r,e){r.exports=require("os")},function(r,e,t){function o(r,e){"string"==typeof r?this.script=r||null:(this.script=null,e=r),this.workers=[],this.tasks=[],e=e||{},this.forkArgs=e.forkArgs||[],this.forkOpts=e.forkOpts||{},this.debugPortStart=e.debugPortStart||43210,this.nodeWorker=e.nodeWorker,e&&"maxWorkers"in e?(n(e.maxWorkers),this.maxWorkers=e.maxWorkers):this.maxWorkers=Math.max((f.cpus||4)-1,1),e&&"minWorkers"in e&&("max"===e.minWorkers?this.minWorkers=Math.max((f.cpus||4)-1,1):(i(e.minWorkers),this.minWorkers=e.minWorkers,this.maxWorkers=Math.max(this.minWorkers,this.maxWorkers)),this._ensureMinWorkers()),this._boundNext=this._next.bind(this),"thread"===this.nodeWorker&&a.ensureWorkerThreads()}function n(r){if(!s(r)||!u(r)||r<1)throw new TypeError("Option maxWorkers must be an integer number >= 1")}function i(r){if(!s(r)||!u(r)||r<0)throw new TypeError("Option minWorkers must be an integer number >= 0")}function s(r){return"number"==typeof r}function u(r){return Math.round(r)==r}var c=t(4),a=t(5),f=t(1);o.prototype.exec=function(r,e){if(e&&!Array.isArray(e))throw new TypeError('Array expected as argument "params"');if("string"==typeof r){var t=c.defer(),o=this.tasks,n={method:r,params:e,resolver:t,timeout:null};o.push(n);var i=t.promise.timeout;return t.promise.timeout=function(r){return-1!==o.indexOf(n)?(n.timeout=r,t.promise):i.call(t.promise,r)},this._next(),t.promise}if("function"==typeof r)return this.exec("run",[String(r),e]);throw new TypeError('Function or string expected as argument "method"')},o.prototype.proxy=function(){if(arguments.length>0)throw new Error("No arguments expected");var r=this;return this.exec("methods").then(function(e){var t={};return e.forEach(function(e){t[e]=function(){return r.exec(e,Array.prototype.slice.call(arguments))}}),t})},o.prototype._next=function(){if(this.tasks.length>0){var r=this._getWorker();if(r){var e=this,t=this.tasks.shift();if(t.resolver.promise.pending){var o=r.exec(t.method,t.params,t.resolver).then(e._boundNext).catch(function(){r.terminated&&(e._removeWorker(r),e._ensureMinWorkers()),e._next()});"number"==typeof t.timeout&&o.timeout(t.timeout)}else e._next()}}},o.prototype._getWorker=function(){for(var r=this.workers,e=0;e<r.length;e++){var t=r[e];if(!1===t.busy())return t}return r.length<this.maxWorkers?(t=new a(this.script,{forkArgs:this.forkArgs,forkOpts:this.forkOpts,debugPort:this.debugPortStart+r.length,nodeWorker:this.nodeWorker}),r.push(t),t):null},o.prototype._removeWorker=function(r){r.terminate(),this._removeWorkerFromList(r)},o.prototype._removeWorkerFromList=function(r){var e=this.workers.indexOf(r);-1!=e&&this.workers.splice(e,1)},o.prototype.terminate=function(r,e){var t=function(r){this._removeWorkerFromList(r)},o=t.bind(this),n=[];return this.workers.slice().forEach(function(t){var i=t.terminateAndNotify(r,e).then(o);n.push(i)}),c.all(n)},o.prototype.clear=function(r){this.terminate(r)},o.prototype.stats=function(){var r=this.workers.length,e=this.workers.filter(function(r){return r.busy()}).length;return{totalWorkers:r,busyWorkers:e,idleWorkers:r-e,pendingTasks:this.tasks.length,activeTasks:e}},o.prototype._ensureMinWorkers=function(){if(this.minWorkers)for(var r=this.workers.length;r<this.minWorkers;r++)this.workers.push(new a(this.script,{forkArgs:this.forkArgs,forkOpts:this.forkOpts,debugPort:this.debugPortStart+r}))},r.exports=o},function(r,e){"use strict";function t(r,e){var s=this;if(!(this instanceof t))throw new SyntaxError("Constructor must be called with the new operator");if("function"!=typeof r)throw new SyntaxError("Function parameter handler(resolve, reject) missing");var u=[],c=[];this.resolved=!1,this.rejected=!1,this.pending=!0;var a=function(r,e){u.push(r),c.push(e)};this.then=function(r,e){return new t(function(t,n){var i=r?o(r,t,n):t,s=e?o(e,t,n):n;a(i,s)},s)};var f=function(r){return s.resolved=!0,s.rejected=!1,s.pending=!1,u.forEach(function(e){e(r)}),a=function(e,t){e(r)},f=p=function(){},s},p=function(r){return s.resolved=!1,s.rejected=!0,s.pending=!1,c.forEach(function(e){e(r)}),a=function(e,t){t(r)},f=p=function(){},s};this.cancel=function(){return e?e.cancel():p(new n),s},this.timeout=function(r){if(e)e.timeout(r);else{var t=setTimeout(function(){p(new i("Promise timed out after "+r+" ms"))},r);s.always(function(){clearTimeout(t)})}return s},r(function(r){f(r)},function(r){p(r)})}function o(r,e,t){return function(o){try{var n=r(o);n&&"function"==typeof n.then&&"function"==typeof n.catch?n.then(e,t):e(n)}catch(r){t(r)}}}function n(r){this.message=r||"promise cancelled",this.stack=(new Error).stack}function i(r){this.message=r||"timeout exceeded",this.stack=(new Error).stack}t.prototype.catch=function(r){return this.then(null,r)},t.prototype.always=function(r){return this.then(r,r)},t.all=function(r){return new t(function(e,t){var o=r.length,n=[];o?r.forEach(function(r,i){r.then(function(r){n[i]=r,0==--o&&e(n)},function(r){o=0,t(r)})}):e(n)})},t.defer=function(){var r={};return r.promise=new t(function(e,t){r.resolve=e,r.reject=t}),r},n.prototype=new Error,n.prototype.constructor=Error,n.prototype.name="CancellationError",t.CancellationError=n,i.prototype=new Error,i.prototype.constructor=Error,i.prototype.name="TimeoutError",t.TimeoutError=i,r.exports=t},function(r,e,t){"use strict";function o(){var r=n("worker_threads");if(!r)throw new Error("WorkerPool: nodeWorkers = thread is not supported, Node >= 11.7.0 required");return r}function n(r){try{return t(7)(r)}catch(r){if("object"==typeof r&&null!==r&&"MODULE_NOT_FOUND"==r.code)return null;throw r}}function i(){if("browser"==l.platform){if("undefined"==typeof Blob)throw new Error("Blob not supported by the browser");if(!window.URL||"function"!=typeof window.URL.createObjectURL)throw new Error("URL.createObjectURL not supported by the browser");var r=new Blob([t(8)],{type:"text/javascript"});return window.URL.createObjectURL(r)}return __dirname+"/worker.js"}function s(r,e){var t=new e(r);return t.on=function(r,e){this.addEventListener(r,function(r){e(r.data)})},t.send=function(r){this.postMessage(r)},t}function u(r,e){var t=new e.Worker(r,{stdout:!1,stderr:!1});return t.send=function(r){this.postMessage(r)},t.kill=function(){this.terminate()},t.disconnect=function(){this.terminate()},t}function c(r,e,t){return t.fork(r,e.forkArgs,e.forkOpts)}function a(r){r=r||{};var e=process.execArgv.join(" "),t=-1!==e.indexOf("--inspect"),o=-1!==e.indexOf("--debug-brk"),n=[];return t&&(n.push("--inspect="+r.debugPort),o&&n.push("--debug-brk")),h({},r,{forkArgs:r.forkArgs,forkOpts:h({},r.forkOpts,{execArgv:(r.forkOpts&&r.forkOpts.execArgv||[]).concat(n)})})}function f(r){for(var e=new Error(""),t=Object.keys(r),o=0;o<t.length;o++)e[t[o]]=r[t[o]];return e}function p(r,e){function n(r){k.terminated=!0,k.terminating&&k.terminationHandler&&k.terminationHandler(k),k.terminating=!1;for(var e in k.processing)void 0!==k.processing[e]&&k.processing[e].resolver.reject(r);k.processing=Object.create(null)}function p(){k.requestQueue.forEach(k.worker.send.bind(k.worker)),k.requestQueue=[]}this.script=r||i();var d=e||{};if("browser"==l.platform){if("function"!=typeof Worker&&("object"!=typeof Worker||"function"!=typeof Worker.prototype.constructor))throw new Error("WorkerPool: Web workers not supported by the browser");this.worker=s(this.script,Worker)}else if("thread"===d.nodeWorker){var h=o();this.worker=u(this.script,h)}else this.worker="auto"===d.nodeWorker&&h?u(this.script,h):c(this.script,a(d),t(12));var k=this;r||(this.worker.ready=!0),this.requestQueue=[],this.worker.on("message",function(r){if("string"==typeof r&&"ready"===r)k.worker.ready=!0,p();else{var e=r.id,t=k.processing[e];void 0!==t&&(delete k.processing[e],!0===k.terminating&&k.terminate(),r.error?t.resolver.reject(f(r.error)):t.resolver.resolve(r.result))}}),this.worker.on("error",n),this.worker.on("exit",function(){n(new Error("Worker terminated unexpectedly"))}),this.processing=Object.create(null),this.terminating=!1,this.terminated=!1,this.terminationHandler=null,this.lastId=0}var d=t(4),h=t(6),l=t(1);p.prototype.methods=function(){return this.exec("methods")},p.prototype.exec=function(r,e,t){t||(t=d.defer());var o=++this.lastId;this.processing[o]={id:o,resolver:t};var n={id:o,method:r,params:e};this.terminated?t.reject(new Error("Worker is terminated")):this.worker.ready?this.worker.send(n):this.requestQueue.push(n);var i=this;return t.promise.catch(function(r){if(!(r instanceof d.CancellationError||r instanceof d.TimeoutError))throw r;delete i.processing[o],i.terminate(!0)}),t.promise},p.prototype.busy=function(){return Object.keys(this.processing).length>0},p.prototype.terminate=function(r,e){if(r){for(var t in this.processing)void 0!==this.processing[t]&&this.processing[t].resolver.reject(new Error("Worker terminated"));this.processing=Object.create(null)}if("function"==typeof e&&(this.terminationHandler=e),this.busy())this.terminating=!0;else{if(this.worker){if("function"==typeof this.worker.kill)this.worker.kill();else{if("function"!=typeof this.worker.terminate)throw new Error("Failed to terminate worker");this.worker.terminate()}this.worker=null}this.terminating=!1,this.terminated=!0,this.terminationHandler&&this.terminationHandler(this)}},p.prototype.terminateAndNotify=function(r,e){var t=d.defer();return e&&(t.promise.timeout=e),this.terminate(r,function(r){t.resolve(r)}),t.promise},r.exports=p,r.exports._tryRequire=n,r.exports._setupProcessWorker=c,r.exports._setupBrowserWorker=s,r.exports._setupWorkerThreadWorker=u,r.exports.ensureWorkerThreads=o},function(r,e){/* | ||
object-assign | ||
@@ -32,3 +32,3 @@ (c) Sindre Sorhus | ||
*/ | ||
"use strict";function t(r){if(null===r||void 0===r)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(r)}var o=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable;r.exports=function(){try{if(!Object.assign)return!1;var r=new String("abc");if(r[5]="de","5"===Object.getOwnPropertyNames(r)[0])return!1;for(var e={},t=0;t<10;t++)e["_"+String.fromCharCode(t)]=t;if("0123456789"!==Object.getOwnPropertyNames(e).map(function(r){return e[r]}).join(""))return!1;var o={};return"abcdefghijklmnopqrst".split("").forEach(function(r){o[r]=r}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},o)).join("")}catch(r){return!1}}()?Object.assign:function(r,e){for(var s,c,u=t(r),a=1;a<arguments.length;a++){s=Object(arguments[a]);for(var f in s)n.call(s,f)&&(u[f]=s[f]);if(o){c=o(s);for(var p=0;p<c.length;p++)i.call(s,c[p])&&(u[c[p]]=s[c[p]])}}return u}},function(r,e){r.exports='!function(r){function e(n){if(o[n])return o[n].exports;var t=o[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,e),t.loaded=!0,t.exports}var o={};e.m=r,e.c=o,e.p="",e(0)}([function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,o){return Object.defineProperty(e,o,{value:r[o],enumerable:!0})},{})}function isPromise(r){return r&&"function"==typeof r.then&&"function"==typeof r.catch}var worker={};if("undefined"!=typeof self&&"function"==typeof postMessage&&"function"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if("undefined"==typeof process)throw new Error("Script must be executed as a worker");worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval("("+fn+")");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on("message",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error(\'Unknown method "\'+r.method+\'"\');var o=e.apply(e,r.params);isPromise(o)?o.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:o,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send("ready")},exports.add=worker.register}]);'},function(r,e){r.exports=require("child_process")},function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,t){return Object.defineProperty(e,t,{value:r[t],enumerable:!0})},{})}function isPromise(r){return r&&"function"==typeof r.then&&"function"==typeof r.catch}var worker={};if("undefined"!=typeof self&&"function"==typeof postMessage&&"function"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if("undefined"==typeof process)throw new Error("Script must be executed as a worker");worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval("("+fn+")");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on("message",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error('Unknown method "'+r.method+'"');var t=e.apply(e,r.params);isPromise(t)?t.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:t,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send("ready")},exports.add=worker.register}])}); | ||
"use strict";function t(r){if(null===r||void 0===r)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(r)}var o=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable;r.exports=function(){try{if(!Object.assign)return!1;var r=new String("abc");if(r[5]="de","5"===Object.getOwnPropertyNames(r)[0])return!1;for(var e={},t=0;t<10;t++)e["_"+String.fromCharCode(t)]=t;if("0123456789"!==Object.getOwnPropertyNames(e).map(function(r){return e[r]}).join(""))return!1;var o={};return"abcdefghijklmnopqrst".split("").forEach(function(r){o[r]=r}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},o)).join("")}catch(r){return!1}}()?Object.assign:function(r,e){for(var s,u,c=t(r),a=1;a<arguments.length;a++){s=Object(arguments[a]);for(var f in s)n.call(s,f)&&(c[f]=s[f]);if(o){u=o(s);for(var p=0;p<u.length;p++)i.call(s,u[p])&&(c[u[p]]=s[u[p]])}}return c}},function(r,e,t){function o(r){return t(n(r))}function n(r){return i[r]||function(){throw new Error("Cannot find module '"+r+"'.")}()}var i={"./Pool":3,"./Pool.js":3,"./Promise":4,"./Promise.js":4,"./WorkerHandler":5,"./WorkerHandler.js":5,"./environment":1,"./environment.js":1,"./generated/embeddedWorker":8,"./generated/embeddedWorker.js":8,"./header":9,"./header.js":9,"./worker":10,"./worker.js":10};o.keys=function(){return Object.keys(i)},o.resolve=n,r.exports=o,o.id=7},function(r,e){r.exports='!function(r){function e(n){if(o[n])return o[n].exports;var t=o[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,e),t.loaded=!0,t.exports}var o={};e.m=r,e.c=o,e.p="",e(0)}([function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,o){return Object.defineProperty(e,o,{value:r[o],enumerable:!0})},{})}function isPromise(r){return r&&"function"==typeof r.then&&"function"==typeof r.catch}var worker={};if("undefined"!=typeof self&&"function"==typeof postMessage&&"function"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if("undefined"==typeof process)throw new Error("Script must be executed as a worker");var WorkerThreads;try{WorkerThreads=__webpack_require__(!function(){var r=new Error(\'Cannot find module "worker_threads"\');throw r.code="MODULE_NOT_FOUND",r}())}catch(r){if("object"!=typeof r||null===r||"MODULE_NOT_FOUND"!=r.code)throw r}if(WorkerThreads&&null!==WorkerThreads.parentPort){var parentPort=WorkerThreads.parentPort;worker.send=parentPort.postMessage.bind(parentPort),worker.on=parentPort.on.bind(parentPort)}else worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval("("+fn+")");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on("message",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error(\'Unknown method "\'+r.method+\'"\');var o=e.apply(e,r.params);isPromise(o)?o.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:o,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send("ready")},exports.add=worker.register}]);'},function(r,e){},function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,t){return Object.defineProperty(e,t,{value:r[t],enumerable:!0})},{})}function isPromise(r){return r&&"function"==typeof r.then&&"function"==typeof r.catch}var worker={};if("undefined"!=typeof self&&"function"==typeof postMessage&&"function"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if("undefined"==typeof process)throw new Error("Script must be executed as a worker");var WorkerThreads;try{WorkerThreads=__webpack_require__(11)}catch(r){if("object"!=typeof r||null===r||"MODULE_NOT_FOUND"!=r.code)throw r}if(WorkerThreads&&null!==WorkerThreads.parentPort){var parentPort=WorkerThreads.parentPort;worker.send=parentPort.postMessage.bind(parentPort),worker.on=parentPort.on.bind(parentPort)}else worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval("("+fn+")");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on("message",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error('Unknown method "'+r.method+'"');var t=e.apply(e,r.params);isPromise(t)?t.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:t,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send("ready")},exports.add=worker.register},function(r,e){r.exports=require("worker_threads")},function(r,e){r.exports=require("child_process")}])}); | ||
//# sourceMappingURL=workerpool.map |
@@ -5,2 +5,8 @@ # workerpool history | ||
## 2019-02-17, version 3.1.0 | ||
- Implemented support for using `worker_threads` in Node.js, via the new option | ||
`nodeWorker: 'thread'`. Thanks @stefanpenner. | ||
## 2018-12-11, version 3.0.0 | ||
@@ -7,0 +13,0 @@ |
@@ -6,2 +6,2 @@ /** | ||
*/ | ||
module.exports = "!function(r){function e(n){if(o[n])return o[n].exports;var t=o[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,e),t.loaded=!0,t.exports}var o={};e.m=r,e.c=o,e.p=\"\",e(0)}([function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,o){return Object.defineProperty(e,o,{value:r[o],enumerable:!0})},{})}function isPromise(r){return r&&\"function\"==typeof r.then&&\"function\"==typeof r.catch}var worker={};if(\"undefined\"!=typeof self&&\"function\"==typeof postMessage&&\"function\"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if(\"undefined\"==typeof process)throw new Error(\"Script must be executed as a worker\");worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval(\"(\"+fn+\")\");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on(\"message\",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error('Unknown method \"'+r.method+'\"');var o=e.apply(e,r.params);isPromise(o)?o.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:o,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send(\"ready\")},exports.add=worker.register}]);"; | ||
module.exports = "!function(r){function e(n){if(o[n])return o[n].exports;var t=o[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,e),t.loaded=!0,t.exports}var o={};e.m=r,e.c=o,e.p=\"\",e(0)}([function(module,exports,__webpack_require__){function convertError(r){return Object.getOwnPropertyNames(r).reduce(function(e,o){return Object.defineProperty(e,o,{value:r[o],enumerable:!0})},{})}function isPromise(r){return r&&\"function\"==typeof r.then&&\"function\"==typeof r.catch}var worker={};if(\"undefined\"!=typeof self&&\"function\"==typeof postMessage&&\"function\"==typeof addEventListener)worker.on=function(r,e){addEventListener(r,function(r){e(r.data)})},worker.send=function(r){postMessage(r)};else{if(\"undefined\"==typeof process)throw new Error(\"Script must be executed as a worker\");var WorkerThreads;try{WorkerThreads=__webpack_require__(!function(){var r=new Error('Cannot find module \"worker_threads\"');throw r.code=\"MODULE_NOT_FOUND\",r}())}catch(r){if(\"object\"!=typeof r||null===r||\"MODULE_NOT_FOUND\"!=r.code)throw r}if(WorkerThreads&&null!==WorkerThreads.parentPort){var parentPort=WorkerThreads.parentPort;worker.send=parentPort.postMessage.bind(parentPort),worker.on=parentPort.on.bind(parentPort)}else worker.on=process.on.bind(process),worker.send=process.send.bind(process)}worker.methods={},worker.methods.run=function run(fn,args){var f=eval(\"(\"+fn+\")\");return f.apply(f,args)},worker.methods.methods=function(){return Object.keys(worker.methods)},worker.on(\"message\",function(r){try{var e=worker.methods[r.method];if(!e)throw new Error('Unknown method \"'+r.method+'\"');var o=e.apply(e,r.params);isPromise(o)?o.then(function(e){worker.send({id:r.id,result:e,error:null})}).catch(function(e){worker.send({id:r.id,result:null,error:convertError(e)})}):worker.send({id:r.id,result:o,error:null})}catch(e){worker.send({id:r.id,result:null,error:convertError(e)})}}),worker.register=function(r){if(r)for(var e in r)r.hasOwnProperty(e)&&(worker.methods[e]=r[e]);worker.send(\"ready\")},exports.add=worker.register}]);"; |
@@ -28,2 +28,3 @@ var Promise = require('./Promise'); | ||
this.debugPortStart = options.debugPortStart || 43210; | ||
this.nodeWorker = options.nodeWorker; | ||
@@ -49,4 +50,12 @@ // configuration | ||
} | ||
this._boundNext = this._next.bind(this); | ||
if (this.nodeWorker === 'thread') { | ||
WorkerHandler.ensureWorkerThreads(); | ||
} | ||
} | ||
/** | ||
@@ -192,5 +201,3 @@ * Execute a function on a worker. | ||
var promise = worker.exec(task.method, task.params, task.resolver) | ||
.then(function () { | ||
me._next(); // trigger next task in the queue | ||
}) | ||
.then(me._boundNext) | ||
.catch(function () { | ||
@@ -229,5 +236,6 @@ // if the worker crashed and terminated, remove it from the pool | ||
// find a non-busy worker | ||
for (var i = 0, ii = this.workers.length; i < ii; i++) { | ||
var worker = this.workers[i]; | ||
if (!worker.busy()) { | ||
var workers = this.workers; | ||
for (var i = 0; i < workers.length; i++) { | ||
var worker = workers[i]; | ||
if (worker.busy() === false) { | ||
return worker; | ||
@@ -237,3 +245,3 @@ } | ||
if (this.workers.length < this.maxWorkers) { | ||
if (workers.length < this.maxWorkers) { | ||
// create a new worker | ||
@@ -243,5 +251,6 @@ worker = new WorkerHandler(this.script, { | ||
forkOpts: this.forkOpts, | ||
debugPort: this.debugPortStart + this.workers.length | ||
debugPort: this.debugPortStart + workers.length, | ||
nodeWorker: this.nodeWorker | ||
}); | ||
this.workers.push(worker); | ||
workers.push(worker); | ||
return worker; | ||
@@ -248,0 +257,0 @@ } |
@@ -76,5 +76,3 @@ 'use strict'; | ||
_resolve = _reject = function () { | ||
throw new Error('Promise is already resolved'); | ||
}; | ||
_resolve = _reject = function () { }; | ||
@@ -103,5 +101,3 @@ return me; | ||
_resolve = _reject = function () { | ||
throw new Error('Promise is already resolved'); | ||
}; | ||
_resolve = _reject = function () { } | ||
@@ -108,0 +104,0 @@ return me; |
@@ -22,4 +22,24 @@ /** | ||
// node.js | ||
worker.on = process.on.bind(process); | ||
worker.send = process.send.bind(process); | ||
var WorkerThreads; | ||
try { | ||
WorkerThreads = require('worker_threads'); | ||
} catch(error) { | ||
if (typeof error === 'object' && error !== null && error.code == 'MODULE_NOT_FOUND') { | ||
// no worker_threads, fallback to sub-process based workers | ||
} else { | ||
throw error; | ||
} | ||
} | ||
if (WorkerThreads && | ||
/* if there is a parentPort, we are in a WorkerThread */ | ||
WorkerThreads.parentPort !== null) { | ||
var parentPort = WorkerThreads.parentPort; | ||
worker.send = parentPort.postMessage.bind(parentPort); | ||
worker.on = parentPort.on.bind(parentPort); | ||
} else { | ||
worker.on = process.on.bind(process); | ||
worker.send = process.send.bind(process); | ||
} | ||
} | ||
@@ -26,0 +46,0 @@ else { |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var Promise = require('./Promise'); | ||
@@ -7,2 +9,24 @@ var assign = require('object-assign'); | ||
function ensureWorkerThreads() { | ||
var WorkerThreads = tryRequire('worker_threads') | ||
if (!WorkerThreads) { | ||
throw new Error('WorkerPool: nodeWorkers = thread is not supported, Node >= 11.7.0 required') | ||
} | ||
return WorkerThreads; | ||
} | ||
function tryRequire(moduleName) { | ||
try { | ||
return require(moduleName); | ||
} catch(error) { | ||
if (typeof error === 'object' && error !== null && error.code == 'MODULE_NOT_FOUND') { | ||
return null; | ||
// no worker_threads, fallback to sub-process based workers | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
// get the default worker script | ||
@@ -29,2 +53,48 @@ function getDefaultWorker() { | ||
function setupBrowserWorker(script, Worker) { | ||
// create the web worker | ||
var worker = new Worker(script); | ||
// add node.js API to the web worker | ||
worker.on = function (event, callback) { | ||
this.addEventListener(event, function (message) { | ||
callback(message.data); | ||
}); | ||
}; | ||
worker.send = function (message) { | ||
this.postMessage(message); | ||
}; | ||
return worker; | ||
} | ||
function setupWorkerThreadWorker(script, WorkerThreads) { | ||
var worker = new WorkerThreads.Worker(script, { | ||
stdout: false, // automatically pipe worker.STDOUT to process.STDOUT | ||
stderr: false // automatically pipe worker.STDERR to process.STDERR | ||
}); | ||
// make the worker mimic a child_process | ||
worker.send = function(message) { | ||
this.postMessage(message); | ||
}; | ||
worker.kill = function() { | ||
this.terminate(); | ||
}; | ||
worker.disconnect = function() { | ||
this.terminate(); | ||
}; | ||
return worker; | ||
} | ||
function setupProcessWorker(script, options, child_process) { | ||
// no WorkerThreads, fallback to sub-process based workers | ||
return child_process.fork( | ||
script, | ||
options.forkArgs, | ||
options.forkOpts | ||
); | ||
} | ||
// add debug flags to child processes if the node inspector is active | ||
@@ -51,3 +121,3 @@ function resolveForkOptions(opts) { | ||
execArgv: (opts.forkOpts && opts.forkOpts.execArgv || []) | ||
.concat(execArgv) | ||
.concat(execArgv) | ||
}) | ||
@@ -80,7 +150,6 @@ }); | ||
*/ | ||
function WorkerHandler(script, options) { | ||
function WorkerHandler(script, _options) { | ||
this.script = script || getDefaultWorker(); | ||
var options = _options || {}; | ||
var forkOptions; | ||
if (environment.platform == 'browser') { | ||
@@ -90,29 +159,22 @@ // check whether Worker is supported by the browser | ||
if (typeof Worker !== 'function' && (typeof Worker !== 'object' || typeof Worker.prototype.constructor !== 'function')) { | ||
throw new Error('Web workers not supported by the browser'); | ||
throw new Error('WorkerPool: Web workers not supported by the browser'); | ||
} | ||
// create the web worker | ||
this.worker = new Worker(this.script); | ||
this.worker = setupBrowserWorker(this.script, Worker); | ||
} else { | ||
// add node.js API to the web worker | ||
this.worker.on = function (event, callback) { | ||
this.addEventListener(event, function (message) { | ||
callback(message.data); | ||
}); | ||
}; | ||
this.worker.send = function (message) { | ||
this.postMessage(message); | ||
}; | ||
if (options.nodeWorker === 'thread') { | ||
var WorkerThreads = ensureWorkerThreads(); | ||
this.worker = setupWorkerThreadWorker(this.script, WorkerThreads); | ||
} else if (options.nodeWorker === 'auto') { | ||
if (WorkerThreads) { | ||
this.worker = setupWorkerThreadWorker(this.script, WorkerThreads); | ||
} else { | ||
this.worker = setupProcessWorker(this.script, resolveForkOptions(options), require('child_process')); | ||
} | ||
} else { | ||
this.worker = setupProcessWorker(this.script, resolveForkOptions(options), require('child_process')); | ||
} | ||
} | ||
else { | ||
// on node.js, create a child process | ||
forkOptions = resolveForkOptions(options); | ||
this.worker = require('child_process').fork( | ||
this.script, | ||
forkOptions.forkArgs, | ||
forkOptions.forkOpts | ||
); | ||
} | ||
var me = this; | ||
@@ -135,3 +197,3 @@ | ||
var task = me.processing[id]; | ||
if (task) { | ||
if (task !== undefined) { | ||
// remove the task from the queue | ||
@@ -141,3 +203,3 @@ delete me.processing[id]; | ||
// test if we need to terminate | ||
if (me.terminating) { | ||
if (me.terminating === true) { | ||
// complete worker termination if all tasks are finished | ||
@@ -167,7 +229,7 @@ me.terminate(); | ||
for (var id in me.processing) { | ||
if (me.processing.hasOwnProperty(id)) { | ||
if (me.processing[id] !== undefined) { | ||
me.processing[id].resolver.reject(error); | ||
} | ||
} | ||
me.processing = {}; | ||
me.processing = Object.create(null); | ||
} | ||
@@ -189,3 +251,3 @@ | ||
this.processing = {}; // queue with tasks currently in progress | ||
this.processing = Object.create(null); // queue with tasks currently in progress | ||
@@ -246,12 +308,14 @@ this.terminating = false; | ||
resolver.promise | ||
.catch(function (error) { | ||
if (error instanceof Promise.CancellationError || error instanceof Promise.TimeoutError) { | ||
// remove this task from the queue. It is already rejected (hence this | ||
// catch event), and else it will be rejected again when terminating | ||
delete me.processing[id]; | ||
.catch(function (error) { | ||
if (error instanceof Promise.CancellationError || error instanceof Promise.TimeoutError) { | ||
// remove this task from the queue. It is already rejected (hence this | ||
// catch event), and else it will be rejected again when terminating | ||
delete me.processing[id]; | ||
// terminate worker | ||
me.terminate(true); | ||
} | ||
}); | ||
// terminate worker | ||
me.terminate(true); | ||
} else { | ||
throw error; | ||
} | ||
}); | ||
@@ -281,7 +345,7 @@ return resolver.promise; | ||
for (var id in this.processing) { | ||
if (this.processing.hasOwnProperty(id)) { | ||
if (this.processing[id] !== undefined) { | ||
this.processing[id].resolver.reject(new Error('Worker terminated')); | ||
} | ||
} | ||
this.processing = {}; | ||
this.processing = Object.create(null); | ||
} | ||
@@ -340,1 +404,6 @@ | ||
module.exports = WorkerHandler; | ||
module.exports._tryRequire = tryRequire; | ||
module.exports._setupProcessWorker = setupProcessWorker; | ||
module.exports._setupBrowserWorker = setupBrowserWorker; | ||
module.exports._setupWorkerThreadWorker = setupWorkerThreadWorker; | ||
module.exports.ensureWorkerThreads = ensureWorkerThreads; |
{ | ||
"name": "workerpool", | ||
"license": "Apache-2.0", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"description": "Offload tasks to a pool of workers on node.js and in the browser", | ||
@@ -24,3 +24,4 @@ "homepage": "https://github.com/josdejong/workerpool", | ||
"test": "mocha test --timeout 10000", | ||
"coverage": "istanbul cover _mocha -- test; echo \"\nCoverage report is available at ./coverage/lcov-report/index.html\"" | ||
"coverage": "istanbul cover _mocha -- test; echo \"\nCoverage report is available at ./coverage/lcov-report/index.html\"", | ||
"prepublishOnly": "npm run build && npm run test" | ||
}, | ||
@@ -27,0 +28,0 @@ "devDependencies": { |
# workerpool | ||
JavaScript is based upon a single event loop which handles one event at a time. Jeremy Epstein [explains this clearly](http://greenash.net.au/thoughts/2012/11/nodejs-itself-is-blocking-only-its-io-is-non-blocking/): | ||
> In Node.js everything runs in parallel, except your code. | ||
> What this means is that all I/O code that you write in Node.js is non-blocking, | ||
> while (conversely) all non-I/O code that you write in Node.js is blocking. | ||
This means that CPU heavy tasks will block other tasks from being executed. In case of a browser environment, the browser will not react to user events like a mouse click while executing a CPU intensive task (the browser "hangs"). In case of a node.js server, the server will not respond to any new request while executing a single, heavy request. | ||
For front-end processes, this is not a desired situation. | ||
Therefore, CPU intensive tasks should be offloaded from the main event loop onto dedicated *workers*. In a browser environment, [Web Workers](http://www.html5rocks.com/en/tutorials/workers/basics/) can be used. In node.js, [child processes](http://nodejs.org/api/child_process.html) are available. An application should be split in separate, decoupled parts, which can run independent of each other in a parallelized way. Effectively, this results in an architecture which achieves concurrency by means of isolated processes and message passing. | ||
**workerpool** offers an easy way to create a pool of workers for both dynamically offloading computations as well as managing a pool of dedicated workers. **workerpool** basically implements a [thread pool pattern](http://en.wikipedia.org/wiki/Thread_pool_pattern). There is a pool of workers to execute tasks. New tasks are put in a queue. A worker executes one task at a time, and once finished, picks a new task from the queue. Workers can be accessed via a natural, promise based proxy, as if they are available straight in the main application. | ||
@@ -28,5 +17,19 @@ | ||
- Handles crashed workers | ||
- Small: less than 5 kB minified and gzipped | ||
- Small: 5 kB minified and gzipped | ||
## Why | ||
JavaScript is based upon a single event loop which handles one event at a time. Jeremy Epstein [explains this clearly](http://greenash.net.au/thoughts/2012/11/nodejs-itself-is-blocking-only-its-io-is-non-blocking/): | ||
> In Node.js everything runs in parallel, except your code. | ||
> What this means is that all I/O code that you write in Node.js is non-blocking, | ||
> while (conversely) all non-I/O code that you write in Node.js is blocking. | ||
This means that CPU heavy tasks will block other tasks from being executed. In case of a browser environment, the browser will not react to user events like a mouse click while executing a CPU intensive task (the browser "hangs"). In case of a node.js server, the server will not respond to any new request while executing a single, heavy request. | ||
For front-end processes, this is not a desired situation. | ||
Therefore, CPU intensive tasks should be offloaded from the main event loop onto dedicated *workers*. In a browser environment, [Web Workers](http://www.html5rocks.com/en/tutorials/workers/basics/) can be used. In node.js, [child processes](https://nodejs.org/api/child_process.html) and [worker_threads](https://nodejs.org/api/worker_threads.html) are available. An application should be split in separate, decoupled parts, which can run independent of each other in a parallelized way. Effectively, this results in an architecture which achieves concurrency by means of isolated processes and message passing. | ||
## Install | ||
@@ -189,4 +192,9 @@ | ||
The following options are available: | ||
- `minWorkers: number | 'max'`. The minimum number of workers that must be initialized and kept available. Setting this to `'max'` will create `maxWorkers` default workers (see below). | ||
- `maxWorkers: number`. The default number of maxWorkers is the number of CPU's minus one. When the number of CPU's could not be determined (for example in older browsers), `maxWorkers` is set to 3. | ||
- `nodeWorker: 'process' | 'thread' | 'auto'`. | ||
- In case of `'process'` (default), `child_process` will be used. | ||
- In case of `'thread'`, `worker_threads` will be used. If `worker_threads` are not available, an error is thrown. | ||
- In case of `'auto'`, `worker_threads` will be used if available (Node.js >= 11.7.0), else `child_process` will be used as fallback. | ||
@@ -355,3 +363,3 @@ A worker pool contains the following functions: | ||
## Sources of inspiration | ||
## Related libraries | ||
@@ -365,2 +373,3 @@ - https://github.com/learnboost/cluster | ||
- https://github.com/ramesaliyev/EasyWebWorker | ||
- https://github.com/rvagg/node-worker-farm | ||
@@ -408,3 +417,3 @@ | ||
Copyright (C) 2014-2018 Jos de Jong <wjosdejong@gmail.com> | ||
Copyright (C) 2014-2019 Jos de Jong <wjosdejong@gmail.com> | ||
@@ -411,0 +420,0 @@ Licensed under the Apache License, Version 2.0 (the "License"); |
@@ -9,4 +9,48 @@ var assert = require('assert'), | ||
function tryRequire(moduleName) { | ||
try { | ||
return require(moduleName); | ||
} catch(error) { | ||
if (typeof error === 'object' && error !== null && error.code == 'MODULE_NOT_FOUND') { | ||
return null; | ||
// no worker_threads, fallback to sub-process based workers | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
describe('Pool', function () { | ||
describe('nodeWorker', function() { | ||
function add(a,b) { | ||
return a+b; | ||
} | ||
it('supports process', function() { | ||
var pool = new Pool({ nodeWorker: 'process' }); | ||
return pool.exec(add, [3, 4]) | ||
}); | ||
it('supports auto', function() { | ||
var pool = new Pool({ nodeWorker: 'auto' }); | ||
return pool.exec(add, [3, 4]) | ||
}); | ||
var WorkerThreads = tryRequire('worker_threads'); | ||
if (WorkerThreads) { | ||
it('supports thread', function() { | ||
var pool = new Pool({ nodeWorker: 'thread' }); | ||
return pool.exec(add, [3, 4]) | ||
}); | ||
} else { | ||
it('errors when not supporting worker thread', function() { | ||
assert.throws(function() { | ||
var pool = new Pool({ nodeWorker: 'thread' }); | ||
}, /WorkerPool: nodeWorkers = thread is not supported, Node >= 11\.7\.0 required/) | ||
}); | ||
} | ||
}) | ||
it('should offload a function to a worker', function (done) { | ||
@@ -13,0 +57,0 @@ var pool = new Pool({maxWorkers: 10}); |
@@ -59,8 +59,7 @@ var assert = require('assert'), | ||
it('should throw an error when resolving a promise twice', function (done) { | ||
it('should NOT throw an error when resolving a promise twice', function (done) { | ||
new Promise(function (resolve, reject) { | ||
resolve('foo'); | ||
resolve('foo'); | ||
assert.throws(function () {resolve('foo')}, Error); | ||
done(); | ||
@@ -116,8 +115,7 @@ }); | ||
it('should throw an error when rejecting a promise twice', function (done) { | ||
it('should NOT throw an error when rejecting a promise twice', function (done) { | ||
var promise = new Promise(function (resolve, reject) { | ||
reject('foo'); | ||
reject('foo'); | ||
assert.throws(function() {reject('foo')}, Error); | ||
done(); | ||
@@ -124,0 +122,0 @@ }); |
@@ -287,2 +287,122 @@ var assert = require('assert'), | ||
describe('tryRequire', function() { | ||
it('gracefully requires or returns null', function() { | ||
assert.equal(WorkerHandler._tryRequire('nope-nope-missing---never-exists'), null); | ||
assert.equal(WorkerHandler._tryRequire('fs'), require('fs')); | ||
}); | ||
}); | ||
// some unit tests, ensuring we correctly interact with the worker constructors | ||
// these next tests are mock heavy, this is to ensure they can be tested cross platform with confidence | ||
describe('setupProcessWorker', function() { | ||
it('correctly configures a child_process', function() { | ||
var SCRIPT = 'I AM SCRIPT'; | ||
var FORK_ARGS = {}; | ||
var FORK_OPTS = {}; | ||
var RESULT = {}; | ||
var forkCalls = 0; | ||
var child_process = { | ||
fork: function(script, forkArgs, forkOpts) { | ||
forkCalls++; | ||
assert.equal(script, SCRIPT); | ||
assert.equal(forkArgs, FORK_ARGS); | ||
assert.equal(forkOpts, forkOpts); | ||
return RESULT; | ||
} | ||
}; | ||
assert.equal(WorkerHandler._setupProcessWorker(SCRIPT, { | ||
forkArgs: FORK_ARGS, | ||
forkOpts: FORK_OPTS | ||
}, child_process), RESULT); | ||
assert.equal(forkCalls, 1); | ||
}); | ||
}); | ||
describe('setupBrowserWorker', function() { | ||
it('correctly sets up the browser worker', function() { | ||
var SCRIPT = 'the script'; | ||
var postMessage; | ||
var addEventListener; | ||
function Worker(script) { | ||
assert.equal(script, SCRIPT); | ||
} | ||
Worker.prototype.addEventListener = function(eventName, callback) { | ||
addEventListener = { eventName: eventName, callback: callback }; | ||
}; | ||
Worker.prototype.postMessage = function(message) { | ||
postMessage = message; | ||
}; | ||
var worker = WorkerHandler._setupBrowserWorker(SCRIPT, Worker); | ||
assert.ok(worker instanceof Worker); | ||
assert.ok(typeof worker.on === 'function'); | ||
assert.ok(typeof worker.send === 'function'); | ||
assert.equal(addEventListener, undefined); | ||
worker.on('foo', function() {}); | ||
assert.equal(addEventListener.eventName, 'foo'); | ||
assert.ok(typeof addEventListener.callback === 'function'); | ||
assert.equal(postMessage, undefined); | ||
worker.send('the message'); | ||
assert.equal(postMessage, 'the message'); | ||
worker.send('next message'); | ||
assert.equal(postMessage, 'next message'); | ||
}) | ||
}); | ||
describe('setupWorkerThreadWorker', function() { | ||
it('works', function() { | ||
var SCRIPT = 'the script'; | ||
var postMessage; | ||
var addEventListener; | ||
var terminate = 0; | ||
function Worker(script, options) { | ||
assert.equal(script, SCRIPT); | ||
assert.equal(options.stdout, false); | ||
assert.equal(options.stderr, false); | ||
} | ||
Worker.prototype.addEventListener = function(eventName, callback) { | ||
addEventListener = { eventName: eventName, callback: callback }; | ||
}; | ||
Worker.prototype.postMessage = function(message) { | ||
postMessage = message; | ||
}; | ||
Worker.prototype.terminate = function() { | ||
terminate++; | ||
} | ||
var worker = WorkerHandler._setupWorkerThreadWorker(SCRIPT, { Worker: Worker }); | ||
assert.ok(worker instanceof Worker); | ||
// assert.ok(typeof worker.on === 'function'); | ||
assert.ok(typeof worker.send === 'function'); | ||
assert.ok(typeof worker.kill === 'function'); | ||
assert.ok(typeof worker.disconnect === 'function'); | ||
assert.equal(terminate, 0); | ||
worker.kill(); | ||
assert.equal(terminate, 1); | ||
worker.disconnect(); | ||
assert.equal(terminate, 2); | ||
assert.equal(postMessage, undefined); | ||
worker.send('the message'); | ||
assert.equal(postMessage, 'the message'); | ||
worker.send('next message'); | ||
assert.equal(postMessage, 'next message'); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
213713
4475
426
5
11