@yaebal/workers
a tiny worker_threads pool — keep the bot on the main loop and offload only the
CPU-heavy bits to threads.
install
pnpm add @yaebal/workerswhen to reach for it
Most handlers are I/O-bound and are already served by @yaebal/runner's concurrency. Threads help only for genuinely CPU-heavy work: image processing, crypto, heavy parsing. Offload that — not the whole bot.
usage
Register tasks in a worker file, then call them from a handler:
// tasks.ts — runs in a worker thread
import { register } from "@yaebal/workers";
register({
resize: (buf) => sharp(buf).resize(100).toBuffer(),
hash: (s) => crypto.createHash("sha256").update(s).digest("hex"),
});// bot — stays on the main event loop
import { createPool } from "@yaebal/workers";
const pool = createPool(new URL("./tasks.js", import.meta.url), { size: 4 });
bot.on("message:photo", async (ctx) => {
const thumb = await pool.run("resize", await ctx.download()); // → thread → back
await ctx.sendPhoto(media.buffer(thumb));
});how it works
The main thread posts name + arg to the next worker (round-robin); the
worker runs the registered function and posts the result back, resolving the pool.run promise by id. Buffers can be passed as transferables (no copy) via the third
argument. If a worker crashes, in-flight calls reject and the thread is respawned.
api
| export | signature | what |
|---|---|---|
createPool | (file, { size }) | spawn a pool of workers |
pool.run | (name, arg?, transfer?) | run a task; returns a promise |
pool.destroy | () | terminate all workers |
register | (handlers) | called inside the worker file |
The worker file must be a built
.js (or run under a TS loader). Workers don't share
closures with the main thread — they only receive the data you pass to run.