first commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# job-registry
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## 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 typed `JobSchedulerError`.
|
||||
- `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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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 JobRegistry`
|
||||
- `register(name: string, jobId: string): void` — throws `JobSchedulerError` on duplicate name.
|
||||
- `unregister(name: string): boolean` — `true` when removed, `false` when 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`.
|
||||
Reference in New Issue
Block a user