Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

moroutine#

1.0.0#

Major Changes#

  • e46aca0: Unify Task and StreamTask under a single Task<T> type
    • Task<T> is PromiseLike<T> for value tasks, AsyncIterable<T> for streaming tasks, or just the base dispatch shape when unparameterized
    • Balancer.select() receives Task instead of Task<any> | StreamTask<any>
    • Arg<T> simplifies to T | Task<T>
    • Classes renamed to PromiseLikeTask<T> and AsyncIterableTask<T> (internal, prefer Task<T> in type annotations)

Minor Changes#

  • 9ab6016: Graceful async worker pool shutdown

    • await using run = workers(4) waits for in-flight tasks to settle before terminating workers
    • run.signal is an AbortSignal that fires when the pool starts disposing — thread it into tasks for cooperative cancellation
    • workers(size, { shutdownTimeout: ms }) force-terminates workers if graceful shutdown exceeds the timeout
    • Existing using run (sync dispose) still terminates immediately
  • 3612d52: Include main-thread call site in error stack traces

    Errors thrown during task dispatch now have stack traces that show where run(), exec(), or await task was called. The original worker-side error is preserved as err.cause with its own stack pointing to the moroutine source.

    Error: boom
        at trackValue (worker-pool.ts:52:15)
        at async loadUser (user-code.ts:7:3)
        at async main (user-code.ts:11:3) {
      [cause]: Error: boom
          at fixtures/math.ts:6:9    // original throw site on the worker
          at MessagePort.<anonymous> (worker-entry.ts:173:25)
    }
    

    Built-in error subclass identity (TypeError, RangeError, etc.) is preserved on the outer wrapper.

  • 5137201: Preserve error details across worker boundary

    Errors thrown in moroutines now transfer with message, stack, cause, and built-in subclass identity (TypeError, RangeError, etc.) preserved via structured clone. Previously only the message string was kept.

  • d13cd40: Configurable load balancing for worker pools

    • workers(size, { balance: leastBusy() }) routes tasks to the worker with the fewest in-flight tasks
    • roundRobin() cycles through workers in order (default, same as before)
    • Custom balancers implement Balancer.select(workers, task) for full control over scheduling
  • cdccfdb: Per-worker dispatch with assign() and run.workers

    • run.workers exposes a read-only array of WorkerHandles, one per pool worker
    • assign(worker, task) returns a copy of the task pinned to a specific worker
    • worker.exec(task) dispatches directly to a specific worker
    • Channel fan-out no longer requires knowing the worker count

Patch Changes#

  • e2dabc1: Fix pool workers exiting early with top-level await

    Pool workers are now ref'd for the lifetime of the pool, preventing the Node.js event loop from exiting prematurely when using using run = workers() with top-level await. Dedicated workers continue to ref only while tasks are in-flight.

0.1.1#

Patch Changes#

  • 5068c96: Auto-detect and transfer AbortSignal arguments to workers

    AbortSignal args are automatically detected, marked transferable via util.transferableAbortSignal(), and transferred to the worker. Works with regular tasks, streaming moroutines, and dedicated workers.

0.1.0#

Minor Changes#

  • b6d4275: Initial version of moroutine: offload functions to worker threads with shared memory primitives for Node.js.