2.9 KiB
job-registry
(no submodules)
Purpose
Provides a string-to-jobId binding so application code can refer to scheduled jobs by stable name ("nightly-cleanup", "hourly-report") without leaking the scheduler's internal id generator (crypto.randomUUID() by default). The registry is a thin Map wrapper with explicit semantics for duplicate names — it throws rather than silently overwriting, because silent overwrite has been a recurring source of "ghost job" bugs in similar systems where a redeploy registers the same name twice and the original job leaks.
Features
register(name, jobId)— throws on duplicate name with a typedJobSchedulerError.unregister(name)— returns boolean for unambiguous removal semantics.resolve(name) -> jobId | undefined— pure lookup, never throws.list()— frozen snapshot for diagnostics and admin endpoints.- Zero dependencies beyond the package's own error class.
Usage: Basic Example
import { JobRegistry } from "@suaveplan/job-scheduler";
const registry = new JobRegistry();
registry.register("nightly", "uuid-1");
console.log(registry.resolve("nightly")); // "uuid-1"
registry.unregister("nightly");
Usage: Advanced Example
import {
createJobScheduler,
JobRegistry,
JobSchedulerError,
JOB_SCHEDULER_CODES,
} from "@suaveplan/job-scheduler";
const scheduler = createJobScheduler();
const registry = new JobRegistry();
const jobId = scheduler.schedule("0 * * * *", async () => {
// ...
});
registry.register("hourly-report", jobId);
try {
registry.register("hourly-report", "different-id");
} catch (err) {
if (
err instanceof JobSchedulerError &&
err.code === JOB_SCHEDULER_CODES.JOB_NOT_FOUND
) {
// Duplicate-name guard tripped — surface a CLI-friendly message.
}
}
for (const { name, jobId } of registry.list()) {
console.log(name, "->", jobId);
}
API Reference
class JobRegistryregister(name: string, jobId: string): void— throwsJobSchedulerErroron duplicate name.unregister(name: string): boolean—truewhen removed,falsewhen unknown.resolve(name: string): string | undefined— pure lookup.list(): ReadonlyArray<{ name: string; jobId: string }>— frozen snapshot.
Implementation Notes
The duplicate-name branch reuses JOB_SCHEDULER.JOB_NOT_FOUND rather than introducing a fourth registry code. The decision is deliberate: the registry is a 12-line wrapper over Map, and growing the error registry just for it would couple the package's public contract to a peripheral feature. The context payload on the thrown error includes the conflicting name, so consumers branching on the duplicate-name case can recognise it without ambiguity. The registry is not synchronised — concurrent registration from two async tasks may race; if you need atomicity, wrap it in a Mutex from @suaveplan/timing.