Worker Pool

A fixed set of node:worker_threads workers running one script, with a queue in front. CPU-bound work handed to a worker stops blocking the event loop, so a request that hashes, parses or compresses something large does not stall every other request on the process.

The queue is bounded and the tasks are timed. An unbounded queue turns a slow worker into memory growth that ends as an out-of-memory kill, and a task with no timeout turns one wedged worker into a permanently smaller pool. Past the depth, submitting is refused rather than accepted and forgotten; past the timeout, the task is failed and its worker replaced.

The script is a filesystem path and must be absolute. A relative path resolves against whatever the process's working directory happens to be, and a data: or eval: URL would make the pool an arbitrary-code sink; both are refused.

b.workerPool.create(scriptPath, opts?) #

stable0.8.45
{
  size:          number,    // workers; default the CPU count, in [1, 256]
  maxQueueDepth: number,    // queued tasks allowed; default 1024, cap 1048576
  taskTimeoutMs: number,    // per-task ceiling; default 300000, cap 3600000
  onExit:        function,  // (code, worker) when a worker exits
}

Start a pool over scriptPath and answer the handle to work it. The handle carries run(payload), which resolves with what the worker posts back; drain(), which waits for the queued and running tasks to finish; terminate(), which stops the workers; and stats().

size defaults to the CPU count or 2, whichever is larger, and a value passed in must be a whole number in [1, 256] or it throws workerpool/bad-size. maxQueueDepth defaults to 1024 and caps at 1048576 (workerpool/bad-max-queue-depth), and run rejects rather than queueing past it. taskTimeoutMs defaults to five minutes and caps at one hour (workerpool/bad-task-timeout); a task that passes it is failed and its worker is replaced, so one wedged task does not shrink the pool for good. onExit is called when a worker dies, with the pool replacing it either way, and must be a function when supplied (workerpool/bad-on-exit).

A runtime that cannot load node:worker_threads throws workerpool/no-worker-threads.

scriptPath must be absolute and must be a file. A relative path would resolve against the process's working directory, and a data: or eval: URL would make the pool run whatever a caller supplied; both throw workerpool/bad-script-path.

The pool spawns its workers while create runs, so a worker the runtime refuses to start throws workerpool/spawn-failed from this call rather than from the first task.

var b = require("@blamejs/core");
var path = require("node:path");
var pool = b.workerPool.create(path.join(__dirname, "hash-worker.js"), {
  size: 4, taskTimeoutMs: b.constants.TIME.seconds(30),
});
var digest = await pool.run({ bytes: buf });
await pool.drain();
await pool.terminate();

Last updated 2026-10-12T14:21:56.879Z by seeder.