Files
skills/docs/api-stack/api/api-jobs-worker-proxy/src/client/client.md
2026-05-29 08:20:56 +01:00

3.4 KiB

Worker-Side Jobs Proxy Client

(no submodules)

Purpose

createJobsProxyClient(port, opts) is the worker-tier entry point for the @suaveplan/api-jobs-worker-proxy package. It returns an object that implements the JobRegistrationHandle capability slot from @suaveplan/api-types, letting a worker-isolated API plugin register cron and queued jobs even though the actual scheduler runs in the host main process. Every registerCron and registerQueued call stores the handler in a local HandlerRegistry and asynchronously marshals a registerJob RPC to the main side via the supplied MessagePort. When the main scheduler ticks a job, the same port carries a runJob dispatch back to the worker; the local serve-side listener invokes the stored handler under an optional timeout.

Features

  • Implements the exact JobRegistrationHandle surface (registerCron, registerQueued) — no proxy-specific extensions on the public type.
  • Bidirectional over a single port: outbound registration RPCs + inbound runJob dispatch via paired raw RPC client + serve handler.
  • Fire-and-forget registration semantics with an onHandlerError observer for asynchronous rejections (job-not-declared, port closed).
  • Per-handler timeout via handlerTimeoutMs; long-running closures reject with JOBS_PROXY.JOB_TIMEOUT.
  • Idempotent close(reason?) tears down both the RPC client and the serve listener.

Usage: Basic

import { MessageChannel } from "node:worker_threads";
import { createJobsProxyClient } from "@suaveplan/api-jobs-worker-proxy/worker-side";

const channel = new MessageChannel();
const client = createJobsProxyClient(channel.port1);

client.registerCron("rotate-keys", async () => {
    await rotate();
});

Usage: Advanced

import { createJobsProxyClient } from "@suaveplan/api-jobs-worker-proxy/worker-side";

const client = createJobsProxyClient(workerPort, {
    handlerTimeoutMs: 30_000,
    onHandlerError: (err, ctx) => {
        logger.warn({ code: err.code, name: ctx.name, kind: ctx.kind });
    },
});
client.registerQueued("send-email", async (payload) => {
    await mailer.send(payload as MailPayload);
});

API Reference

  • createJobsProxyClient(port, opts?) -> JobsProxyClient — factory.
  • JobsProxyClient extends JobRegistrationHandle — adds close() and a sizes accessor reporting registration counts.
  • JobsProxyClientOptions:
    • handlerTimeoutMs?: number — per-dispatch timeout, 0 disables.
    • onHandlerError?: (err, ctx) => void — observer hook.

Implementation Notes

The client multiplexes a createRawWorkerRpcClient (for outbound registerJob calls) and a serveWorkerRpc handlers object (for inbound runJob) over the same PortLike. Protocol frames partition cleanly: response frames target the RPC client's pending registry, and request frames target the serve dispatcher; each listener silently drops the other's traffic. The local HandlerRegistry is the single source of truth for which handlers can be dispatched — the main side relies on the worker holding the closure and we never serialize the function across the wire. The fire-and-forget registerJob call uses .catch to funnel rejections (including JOB_NOT_DECLARED from main) through onHandlerError, preserving the original JobRegistrationHandle synchronous-void return contract.