MainSDK
Search⌘K
How-to

Run CPU work on workers

Move CPU-heavy work off the request thread with workers.run, a declared module, a time limit and the tenant carried in.

Building for 0.4

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

You will move a CPU-heavy step out of a request handler onto a worker thread, declare the module, set a time limit and test it. It takes about 10 minutes and needs no account.

You need

  • A MainSDK app with a main.yaml.
  • A function that burns CPU for more than a few milliseconds and needs no network, database or secret. A worker may not call other MainSDK interfaces.

1. Declare the module

main.yaml
workers:
  size: auto
  timeout: 10s
  modules: ["src/workers/*.worker.ts"]

2. Write the worker module

src/workers/score.worker.ts
import { worker } from "mainsdk/workers";

export default worker((rows: number[][], ctx) => {
  ctx.log.info("scoring", { rows: rows.length });
  return rows.map((r) => r.reduce((a, b) => a + b, 0));
});

3. Call it

lib/score.ts
import { workers } from "mainsdk";

export function score(rows: number[][], signal?: AbortSignal) {
  return workers.run<number[][], number[]>("./src/workers/score.worker.ts", rows, { signal });
}

Pass plain data in and out. Never pass a secret: it fails with MAIN-WORKER-0004.

4. Test it

createTestApp() runs the task inline. Add workers: "threads" to prove it on a real thread.

test/score.test.ts
import { createTestApp } from "@mainsdk/testing";

const app = createTestApp({ yaml: "schema: 1\nproject: t\nworkers:\n  modules: [src/workers/*.worker.ts]\n", workers: "threads" });
const out = await app.workers.run("./src/workers/score.worker.ts", [[1, 2], [3]]);

Check it worked

  • npx mainsdk check has no MAIN-WORKER- finding, and npx mainsdk discover lists the module.
  • workers.snapshot() shows completed rising and threads back to 0 after the idle time.
  • A task that loops past the timeout fails with MAIN-WORKER-0005 and the next task still runs.

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet