Skip to content

@gj-kit/nest-operations-jobs

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

  • npm 0.1.2
  • 230+ unit tests
  • 11 @ts-expect-error guards
  • 13 store contract cases
  • 0 runtime dependencies

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.

  • 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.

Outcome: An authenticated operations boundary backed by application-owned run storage.

Terminal window
pnpm add @gj-kit/nest-operations-jobs

Implement JobRunStore, then configure a 32+ character shared secret or a token verifier before module registration.

Copy this first, then replace only the app-owned values named above.

import { OperationsJobsModule, type JobRunStore } from '@gj-kit/nest-operations-jobs';
declare const store: JobRunStore; // Your database-backed run store.
declare const secret: string; // At least 32 characters; keep it outside source control.
export const operations = OperationsJobsModule.forRoot({
store,
auth: { secret },
trigger: { path: 'internal/jobs' },
});

error is unreachable until status is narrowed, and recorded sits on every branch because a stored row that disagrees with the returned status is exactly what deserves a page.

import type { JobExecutionResult } from '@gj-kit/nest-operations-jobs/core';
declare const result: JobExecutionResult; // await runner.execute(...)
declare function pageOncall(jobKey: string, runId: string): void; // the app owns this
export function report(): void {
// console.error(result.error.code);
// -> error TS2339: Property 'error' does not exist on type 'JobExecutionResult'.
if (result.status === 'TIMED_OUT') {
console.error(result.jobKey, result.error.code); // 'ERR_JOB_TIMEOUT'
} else if (result.status === 'SKIPPED') {
console.warn(result.jobKey, result.reason); // 'overlap' - the only value
}
// `recorded` sits on every branch: 'superseded' means a reaper already
// finalised the row, so a second body may run under a different runId.
if (result.recorded === 'superseded') pageOncall(result.jobKey, result.runId);
}

Use it when a Nest application needs scheduled or operator-triggered work with explicit concurrency, authorization, and run persistence.

Do not hide product business rules, queue infrastructure, or application authorization policy behind this integration.

Engines: node >=20

Peer Supported range Required for
@nestjs/common `^10
@nestjs/core `^10
reflect-metadata `^0.1.13
rxjs ^7 the package integration
Entry Exported symbols
Root entry 60
./core 61
./testing 13

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

complete API reference contains every public function, class, type, constant, and error contract generated from release declarations. Each item shows its import path, release signature, and package version.

Relationship Package Why combine them
Standalone — This package can be adopted without another GJ Kit package.
Optional companion @gj-kit/nest-notifications Notify operators or users after an application-owned job result.

npm · GitHub