Skip to content

@gj-kit/nest-operations-jobs core concepts

An unauthenticated trigger, or tuning that lets a job run twice, fails before the scheduler’s first call.

Hand-rolled cron endpoints fail while every dashboard stays green. Swallow the whole unique-constraint violation inside your claim and a permanently blocked job becomes a stream of SKIPPED/200 responses; set the stale-run budget below the heartbeat interval and a healthy run looks reapable to the next trigger, which starts a second body. Meanwhile the trigger route ships with a short shared secret compared by ===, the stored run row can disagree with the status you returned without anyone noticing, and a scheduler attempt deadline set under the job’s own timeout records long runs that actually succeeded as failures.

A scheduled or operator-triggered route needs host-owned authorization and durable run storage. The package coordinates execution but never defines business work.

Completed, failed, skipped, and superseded runs do not share fields. Narrowing prevents a summary from claiming an execution state that never happened.

  • Omitting auth is a compile error — auth is a required field of OperationsJobsModuleOptions, so a module wired without it does not type-check. An empty auth, or a secret under 32 characters, throws ERR_JOB_AUTH_MISCONFIGURED while forRoot assembles the module.
  • Result fields exist only after narrowing — On JobExecutionResult, error, reason and summary are unreachable until you switch on status; three @ts-expect-error fixtures pin that.
  • The tuning that voids single execution — createJobRunner throws ERR_JOB_INVALID when staleRunAfterMs is under 2x heartbeatIntervalMs — the floor below which a healthy run’s watermark can outlive the liveness budget between its own beats.
  • Your store’s atomicity, in your suite — jobRunStoreContractCases() returns 13 framework-free cases covering obligations S1-S6 — a concurrent claim burst, two concurrent reaps of the same three rows — that you run against your real database. Supply inspect and it returns 16, adding S7.
  • /core provably contains no Nest — A guard test scans src/core/, src/testing/ and every built dist/core.* and dist/testing.* chunk for @nestjs, rxjs and reflect-metadata, and a control case asserts dist/index.js does contain @nestjs — so an empty result means the scanner actually looked.

Keep job-trigger authorization and app data ownership in the host application. Never turn a convenience route into an unauthenticated operations endpoint.

Continue with the two verified recipes.