Files
suaveplan/packages/foundation/flow/queue-distribution/src/worker/local/local.md
2026-05-27 23:47:53 +01:00

3.4 KiB

LocalWorker

(no submodules)

Purpose

LocalWorker<Ctx> is an in-process executor — it runs DistributedTask.execute directly in the calling JavaScript event loop, with no IO indirection. Use it when the work can run on the same node as the dispatcher: tiny CPU jobs, fan-out across a thread, or local-only test setups. The constructor is parameterised by an ExecutionContext of type Ctx, which the worker passes verbatim into every task.execute(input, ctx) call.

Features

  • Inherits lifecycle, metrics, OTel emission, and FSM from AbstractWorker.
  • Generic over caller-defined ExecutionContext.
  • getCapabilities() advertises { hasFileSystemAccess: true, isRemote: false, contextType } so strategies can route work accordingly.
  • getType() returns "local".

Usage: Basic Example

import { LocalWorker } from "@suaveplan/queue-distribution/worker/local/local";
import type { DistributedTask, ExecutionContext } from "@suaveplan/queue-distribution/task/task";

class EmptyContext implements ExecutionContext {}

const worker = new LocalWorker(new EmptyContext(), { capacity: 4 });
await worker.start();

const task: DistributedTask<number, string> = {
    id: "format-number",
    execute: async (n) => `n=${n}`,
    getStatus: () => "PENDING",
    setStatus: () => {},
    getMetadata: () => ({ createdAt: new Date(), attempts: 0 }),
};

const result = await worker.executeTask(task, 7); // "n=7"

Usage: Advanced Example

Thread your dependency container through the ExecutionContext so every task gets access to the same logger, tracer, and DB client.

import { LocalWorker } from "@suaveplan/queue-distribution/worker/local/local";
import type { DistributedTask, ExecutionContext } from "@suaveplan/queue-distribution/task/task";

interface AppContext extends ExecutionContext {
    logger: { info: (m: string) => void };
    db: { query: (sql: string) => Promise<unknown> };
}

const ctx: AppContext = {
    logger: { info: console.log },
    db: { query: async () => undefined },
};

const worker = new LocalWorker<AppContext>(ctx, { capacity: 8 });
await worker.start();

const task: DistributedTask<string, unknown> = {
    id: "lookup",
    execute: async (sql, c) => (c as AppContext).db.query(sql),
    getStatus: () => "PENDING",
    setStatus: () => {},
    getMetadata: () => ({ createdAt: new Date(), attempts: 0 }),
};

API Reference

  • class LocalWorker<Ctx extends ExecutionContext = ExecutionContext> extends AbstractWorker.
  • constructor(context: Ctx, options?: AbstractWorkerOptions, deps?: AbstractWorkerDeps).
  • protected doExecuteTask<I, O>(task, input): Promise<O> — invokes task.execute(input, this.context).
  • protected getType(): string — returns "local".
  • protected getCapabilities(): Readonly<Record<string, unknown>> — { hasFileSystemAccess: true, isRemote: false, contextType: <ctor name> }.

Implementation Notes

getCapabilities reflects the context constructor name (Object when the context is Object.create(null)) so logs and dashboards can distinguish similarly-typed workers running with different contexts (e.g. tenant-specific). The hasFileSystemAccess: true flag is a best-effort signal — strategies that route IO-heavy work to file-system-aware workers can filter on it. Remote / worker-thread plugins explicitly set isRemote: true or isThreaded: true so the negation is meaningful in dashboards.