Node Worker Pool
node-worker-pool is a JavaScript library for Node.js that provides a robust mechanism for managing a pool of child worker processes. It's designed for scenarios involving numerous highly parallelizable tasks, utilizing an exclusive message-passing paradigm rather than shared memory for inter-process communication. The library, currently at version 3.0.2, allows developers to define custom worker executables (though helper libraries are currently Node.js-specific) that communicate over `stdin`/`stdout` using a defined protocol. While its release cadence isn't explicitly documented, it focuses on stability and efficient task distribution. Key differentiators include its explicit message-passing design and the ability to use external executables as workers, offering flexibility beyond typical Node.js `worker_threads` when process isolation and custom language workers are desired.
Common errors
-
Error: Cannot find module 'node-worker-pool'
cause The `node-worker-pool` package is not installed or not accessible from the current working directory.fixRun `npm install node-worker-pool` or `yarn add node-worker-pool` in your project directory. Ensure your Node.js module resolution paths are correctly configured. -
ReferenceError: WorkerPool is not defined
cause The `WorkerPool` class was used without being correctly `require`d into the scope.fixAdd `const WorkerPool = require('node-worker-pool');` at the top of your file where `WorkerPool` is used. -
Worker protocol error: Response must be an object
cause The `onMessage` function in the worker script returned a value that was not a plain JavaScript object.fixModify your `onMessage` function in the worker script to always return an object, e.g., `return { data: yourResult };`. -
Error: spawn [worker executable path] ENOENT
cause The path provided for the worker executable (e.g., `process.execPath` or a custom binary) or the worker script itself is incorrect or the file does not exist.fixVerify that `process.execPath` correctly points to your Node.js binary and that the `workerScriptPath` argument correctly points to your worker script file. Use absolute paths for robustness.
Warnings
- gotcha The communication protocol between the main process and workers is not officially documented, making it challenging to implement workers in languages other than Node.js or to debug complex communication issues.
- gotcha Worker functions (`onInitialize`, `onMessage`) must only return plain JavaScript objects. Returning primitive values (strings, numbers, booleans) or `null`/`undefined` from `onMessage` will lead to a 'Worker protocol error: Response must be an object'.
- gotcha The `workerExecutablePath` and `workerScriptPath` arguments to `WorkerPool` must be correct and accessible from the main process. Incorrect paths will result in worker startup failures that might be difficult to diagnose.
Install
-
npm install node-worker-pool -
yarn add node-worker-pool -
pnpm add node-worker-pool
Imports
- WorkerPool
import WorkerPool from 'node-worker-pool';
const WorkerPool = require('node-worker-pool'); - workerUtils
import * as workerUtils from 'node-worker-pool/nodeWorkerUtils';
const workerUtils = require('node-worker-pool/nodeWorkerUtils'); - { startWorker, respondWithError }
import { startWorker, respondWithError } from 'node-worker-pool/nodeWorkerUtils';const { startWorker, respondWithError } = require('node-worker-pool/nodeWorkerUtils');
Quickstart
const fs = require('fs');
const path = require('path');
const WorkerPool = require('node-worker-pool');
const workerScriptContent = `
var workerUtils = require('node-worker-pool/nodeWorkerUtils');
var initData;
function onInitialize(data) {
initData = data;
}
function onMessage(data) {
return {
initData: initData,
receivedData: data,
pid: process.pid
};
}
if (require.main === module) {
try {
workerUtils.startWorker(onInitialize, onMessage);
} catch (e) {
workerUtils.respondWithError(e);
}
}
`;
// Create a temporary worker file
const workerFilePath = path.join(__dirname, 'temp-worker.js');
fs.writeFileSync(workerFilePath, workerScriptContent);
async function runPool() {
console.log('Starting worker pool...');
const workerPool = new WorkerPool(
2, // Use 2 workers for demonstration
process.execPath, // Path to the node binary
workerFilePath, // Path to the temporary worker script
{
initData: { someUsefulConstant: 42 }
}
);
try {
console.log('Sending messages to workers...');
const responses = await Promise.all([
workerPool.sendMessage({ message: 'Hello from main 1!' }),
workerPool.sendMessage({ message: 'Hello from main 2!' }),
workerPool.sendMessage({ message: 'Hello from main 3!' })
]);
responses.forEach((response, index) => {
console.log(`Response ${index + 1}:`, response);
});
console.log('Shutting down worker pool...');
await workerPool.shutDown();
console.log('All worker processes have now been killed.');
} catch (error) {
console.error('An error occurred:', error);
} finally {
// Clean up the temporary worker file
fs.unlinkSync(workerFilePath);
process.exit(0);
}
}
runPool();