@gj-kit/nest-operations-jobs
인증 없는 trigger, 그리고 잡을 두 번 돌게 만드는 설정은 scheduler의 첫 호출이 아니라 컴파일과 부팅에서 걸립니다.
- npm
0.1.2 - unit test 230개 이상
- @ts-expect-error 가드 11개
- store 계약 case 13개
- 런타임 의존성 0
계속 학습하기
섹션 제목: “계속 학습하기”왜 필요한가
섹션 제목: “왜 필요한가”직접 만든 cron endpoint의 장애는 대개 모든 대시보드가 초록인 채로 옵니다. claim에서 unique 위반을 통째로 삼키면 영구히 막힌 잡이 SKIPPED/200 스트림으로 둔갑하고, stale 판정 예산을 heartbeat 주기 아래로 내리면 건강한 실행이 다음 trigger에게 reap 대상으로 보여 두 번째 본문이 시작됩니다. 그 사이 trigger route는 짧은 shared secret을 ===로 비교한 채 배포되고, 저장된 실행 기록이 반환된 status와 어긋나도 아무도 모르며, scheduler의 attempt deadline을 잡의 timeout보다 짧게 잡으면 실제로 성공한 긴 실행이 실패로 기록됩니다.
무엇으로 막는가
섹션 제목: “무엇으로 막는가”auth누락은 컴파일 에러입니다 —auth는 OperationsJobsModuleOptions의 필수 필드라, 이걸 빼고 배선한 module은 타입 검사부터 통과하지 못합니다. 빈auth나 32자 미만 secret은 forRoot가 module을 조립하는 시점에 ERR_JOB_AUTH_MISCONFIGURED로 죽습니다.- 결과 필드는 좁힌 뒤에만 존재합니다 — JobExecutionResult에서
error·reason·summary는status로 좁히기 전에는 접근할 수 없습니다. @ts-expect-error 픽스처 3개가 이를 고정합니다. - 단일 실행 보장을 지우는 튜닝을 거부합니다 — staleRunAfterMs가 heartbeatIntervalMs의 2배 미만이면 createJobRunner가 ERR_JOB_INVALID를 던져 부팅을 멈춥니다. 건강한 run의 watermark가 자기 beat 사이에서 liveness 예산보다 오래돼 보일 수 있는 하한입니다.
- 저장소 원자성을 호스트 테스트에서 검사합니다 — jobRunStoreContractCases()는 프레임워크 없는 적합성 케이스 13개를 돌려줍니다. S1–S6 의무를 실제 database에 그대로 겁니다 — 동시 claim burst, 같은 세 행을 노리는 두 개의 동시 reap.
inspect를 넘기면 S7까지 붙어 16개가 됩니다. - /core에 Nest가 없음을 산출물로 증명합니다 — guard test가 src/core/**·src/testing/**와 빌드 산출물 dist/core.·dist/testing. 청크 전량을 훑어 @nestjs·rxjs·reflect-metadata 참조가 하나도 없음을 확인합니다. 같은 파일의 대조군이 dist/index.js에는 @nestjs가 있다고 못 박기 때문에, 빈 결과가 ’스캐너가 아무것도 안 봤다’는 뜻일 수 없습니다.
Golden path
섹션 제목: “Golden path”완료 상태: 앱 소유 실행 저장소로 뒷받침되는 인증된 운영 작업 경계를 만듭니다.
1. 설치
섹션 제목: “1. 설치”pnpm add @gj-kit/nest-operations-jobs2. 앱이 소유할 경계를 정합니다
섹션 제목: “2. 앱이 소유할 경계를 정합니다”JobRunStore를 구현한 뒤 module을 등록하기 전에 32자 이상의 shared secret 또는 token verifier를 설정합니다.
3. 최소 연결부터 시작합니다
섹션 제목: “3. 최소 연결부터 시작합니다”먼저 아래 코드를 복사한 뒤, 위에서 언급한 앱 소유 값만 교체하세요.
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' },});실제로는 이렇게 걸립니다
섹션 제목: “실제로는 이렇게 걸립니다”status로 좁히기 전에는 error에 접근할 수 없고, recorded는 모든 분기에 있습니다. 저장된 행이 반환된 status와 어긋나는 상황이야말로 알림을 걸 지점이기 때문입니다.
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);}사용할 때
섹션 제목: “사용할 때”Nest 앱에서 명시적 동시성, 권한, 실행 영속성을 갖춘 스케줄 또는 운영자 실행 작업이 필요할 때 사용합니다.
사용하지 않을 때
섹션 제목: “사용하지 않을 때”제품 비즈니스 규칙, queue 인프라, 앱 권한 정책을 이 통합 뒤에 숨기지 마세요.
환경과 peer
섹션 제목: “환경과 peer”엔진: node >=20
| Peer | 지원 범위 | 필요한 위치 |
|---|---|---|
@nestjs/common |
`^10 | |
@nestjs/core |
`^10 | |
reflect-metadata |
`^0.1.13 | |
rxjs |
^7 |
패키지 통합 |
공개 subpath
섹션 제목: “공개 subpath”| Entry | Exported symbols |
|---|---|
Root entry |
60 |
./core |
61 |
./testing |
13 |
안전 경계
섹션 제목: “안전 경계”작업 실행 권한과 앱 데이터 소유권은 host 앱에 둡니다. 편의 route를 인증 없는 운영 endpoint로 만들지 마세요.
API reference
섹션 제목: “API reference”전체 API reference에는 선언 파일에서 생성한 모든 공개 함수, 클래스, 타입, 상수, 오류 계약이 있습니다. 각 항목은 import path, release signature, package version을 표시합니다.
패키지 관계
섹션 제목: “패키지 관계”| 관계 | 패키지 | 함께 쓰는 이유 |
|---|---|---|
| 단독 사용 | — | 다른 GJ Kit 패키지 없이 도입할 수 있습니다. |
| 선택 조합 | @gj-kit/nest-notifications |
앱 소유 job 결과 뒤에 운영자나 사용자에게 알릴 때 함께 사용합니다. |