@gj-kit/nest-operations-jobs 핵심 개념
인증 없는 trigger, 그리고 잡을 두 번 돌게 만드는 설정은 scheduler의 첫 호출이 아니라 컴파일과 부팅에서 걸립니다.
왜 이 경계가 필요한가
섹션 제목: “왜 이 경계가 필요한가”직접 만든 cron endpoint의 장애는 대개 모든 대시보드가 초록인 채로 옵니다. claim에서 unique 위반을 통째로 삼키면 영구히 막힌 잡이 SKIPPED/200 스트림으로 둔갑하고, stale 판정 예산을 heartbeat 주기 아래로 내리면 건강한 실행이 다음 trigger에게 reap 대상으로 보여 두 번째 본문이 시작됩니다. 그 사이 trigger route는 짧은 shared secret을 ===로 비교한 채 배포되고, 저장된 실행 기록이 반환된 status와 어긋나도 아무도 모르며, scheduler의 attempt deadline을 잡의 timeout보다 짧게 잡으면 실제로 성공한 긴 실행이 실패로 기록됩니다.
trigger는 운영 경계입니다
섹션 제목: “trigger는 운영 경계입니다”scheduler 또는 운영자 trigger route에는 호스트 소유 authorization과 내구성 실행 저장소가 필요합니다. 패키지는 실행을 조정하지만 비즈니스 작업을 정의하지 않습니다.
실행 상태는 discriminated result입니다
섹션 제목: “실행 상태는 discriminated result입니다”completed, failed, skipped, superseded 실행은 field를 공유하지 않습니다. narrowing하면 발생하지 않은 실행 상태를 summary가 주장하지 않게 됩니다.
패키지가 강제하는 것
섹션 제목: “패키지가 강제하는 것”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가 있다고 못 박기 때문에, 빈 결과가 ’스캐너가 아무것도 안 봤다’는 뜻일 수 없습니다.
앱에 남는 책임
섹션 제목: “앱에 남는 책임”작업 실행 권한과 앱 데이터 소유권은 host 앱에 둡니다. 편의 route를 인증 없는 운영 endpoint로 만들지 마세요.
다음은 검증된 레시피 두 개입니다.