Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
# job-dispatcher
## Purpose
Encapsulates the "hand a job to the executor" step of the scheduler's tick loop. The scheduler core decides *which* job runs next and *when*; this module is responsible for the *how* — wiring the per-attempt `AbortController`, tracking the in-flight promise, and updating per-job counters (`runs`, `failures`, `lastRun`) on settle. Splitting this out keeps the scheduler core under the 300-line file budget and isolates the small but error-prone bookkeeping work in one focused module.
## Features
- Single `dispatch(job, scheduledAt, env)` function — no class, no state of its own.
- Captures the in-flight promise into the scheduler-owned `Set<Promise>` for `stop()` drain.
- Atomically transitions the job to `running` and registers a fresh `AbortController` on the job record.
- Invokes the scheduler's `afterRun` callback in `finally`, regardless of success or failure.
## Usage: Basic Example
```ts
import { dispatch } from "@suaveplan/job-scheduler";
dispatch(scheduledJob, scheduledAt, {
clock,
logger,
events,
timers,
inFlight,
runningSet,
afterRun: (job) => {
// scheduler decides whether to re-enqueue or remove
},
});
```
## Usage: Advanced Example
```ts
import { dispatch, type ScheduledJob } from "@suaveplan/job-scheduler";
function pump(jobs: Iterable<ScheduledJob>): void {
for (const job of jobs) {
if (job.status !== "pending") continue;
dispatch(job, job.nextRun ?? clock(), {
clock,
logger,
events,
timers,
inFlight,
runningSet,
afterRun: (j) => {
if (j.kind === "queued") {
// one-shot — let the scheduler garbage-collect
return;
}
// re-enqueue cron jobs by computing the next fire
},
});
}
}
```
## API Reference
- `dispatch(job: ScheduledJob, scheduledAt: number, env: DispatchEnv): void` — fires the job. No return value; all bookkeeping happens via `env`.
- `interface ScheduledJob` — internal record shape mutated in place.
- `interface DispatchEnv` — `{ clock, logger, events, timers, inFlight, runningSet, afterRun }`.
## Implementation Notes
The `afterRun` callback is the scheduler's hook for "what happens once the job settles" — for queued jobs the scheduler typically deletes the entry; for cron jobs it computes the next `nextRun` and re-enqueues. Putting this branch in the scheduler core (rather than passing a flag to `dispatch`) keeps `dispatch` polymorphism-free and makes the lifecycle of every cron / queued job obvious at the call site. The promise is tracked in `env.inFlight` so `JobScheduler.stop()` can `Promise.allSettled` over the set and drain the in-flight work cleanly.