Files
2026-05-27 23:29:53 +01:00

2.5 KiB

Handler Bridge

(no submodules)

Purpose

This module owns the shared wire schemas, the worker-side HandlerRegistry, and the runWithTimeout helper used by both ends of the proxy. The bridge is the only place that decides how a registered cron/queued handler is exercised on the worker side; isolating it keeps the client and server modules small and lets the same logic be unit tested without spinning up a MessageChannel. Schemas use zod so any bad payload that crosses the boundary fails fast at the parse step rather than producing an obscure runtime error downstream.

Features

  • registerJobRequestSchema / runJobRequestSchema — Zod-validated wire formats for registration and dispatch frames.
  • HandlerRegistry — type-safe storage of cron + queued closures with idempotent set / run / clear semantics and a sizes accessor.
  • runWithTimeout — runs a closure with an optional millisecond budget and wraps every failure into a typed JobsProxyError (HANDLER_THREW or JOB_TIMEOUT).

Usage: Basic

import { HandlerRegistry } from "@suaveplan/api-jobs-worker-proxy/handler-bridge";

const reg = new HandlerRegistry();
reg.setCron("daily-rotate", async () => rotate());
await reg.runCron("daily-rotate");

Usage: Advanced

import { runWithTimeout } from "@suaveplan/api-jobs-worker-proxy/handler-bridge";

await runWithTimeout(
    () => longRunningExport(),
    "export-csv",
    30_000,
); // throws JobsProxyError("JOBS_PROXY.JOB_TIMEOUT") after 30s

API Reference

  • registerJobRequestSchema: ZodType<RegisterJobRequest> — wire schema.
  • runJobRequestSchema: ZodType<RunJobRequest> — wire schema.
  • HandlerRegistry — setCron, setQueued, hasCron, hasQueued, runCron, runQueued, clear, sizes.
  • runWithTimeout(fn, name, timeoutMs) — runs fn, wraps failures.

Implementation Notes

runWithTimeout uses Promise.race between the handler invocation and a timeout-rejecting promise. The timeout branch always installs a timer (non-nullable) when timeoutMs > 0; the finally-clear is unconditional once that branch is entered. A 0 budget skips the race entirely and falls back to a direct await so successful handlers do not pay the extra microtask cost. HandlerRegistry.setCron/setQueued return a boolean indicating whether the name already existed, allowing callers to detect (and warn on) duplicate registrations without forbidding the replacement.