Skip to content

5 · Cron jobs — ไม่มี in-process scheduler

บทนี้ยืนยันด้วยหลักฐานจากโค้ดว่า recruitment-api (branch: prod) ไม่มี cron job / background scheduler ในตัว process เลย — ต่างจาก benefit-api (มี @nestjs/schedule + CronTabService) และ 2way-api (มี src/crontab/ + 3 cron active เวลา 07:00)

ทุกงานที่ดู "คล้าย batch" (ส่งอีเมลประกาศผล, export-to-HRMI, ลด remainingManpower, PDPA delete cascade) ถูก trigger แบบ synchronous ภายใน HTTP request-response ไม่มี worker / queue / k8s CronJob ที่อ้างอิงจาก repo นี้


สรุปคำตัดสิน (หนึ่งบรรทัด)

คำถามคำตอบหลักฐาน
มี @nestjs/schedule ใน dependencies ไหม?ไม่มีrecruitment-api/package.json (branch: prod) — grep @nestjs/schedule = 0 match
มี @Cron / CronExpression / ScheduleModule ใน src/ หรือ libs/ ไหม?ไม่มีgrep ทั้ง repo บน branch prod = 0 match
มีโฟลเดอร์ src/crontab/ หรือ src/cron/ ไหม?ไม่มีโครงสร้างโฟลเดอร์ใน 01 Repository map
มี Bull / BullMQ / Agenda / node-cron ไหม?ไม่มีpackage.json dependencies ไม่มีชื่อเหล่านี้
แล้วงาน batch ทำที่ไหน?ใน request handler ของ feature moduleดูตารางด้านล่าง

วิธีตรวจสอบซ้ำ (re-verify checklist)

รันบน branch prod ของ recruitment-api:

bash
# 1) dependency
grep -n '@nestjs/schedule\|node-cron\|bullmq\|bull\|agenda' package.json
# คาดหวัง: ไม่มีผลลัพธ์

# 2) decorator / module
rg -n '@Cron|ScheduleModule|CronExpression|CronJob' src libs
# คาดหวัง: ไม่มีผลลัพธ์

# 3) โฟลเดอร์
ls src/crontab src/cron 2>&1
# คาดหวัง: No such file or directory

เทียบกับ repo ที่ มี cron จริง:

Repoมี @nestjs/scheduleมี @Cron activeโฟลเดอร์
benefit-api (prod)ใช่ (package.json:33)2 jobs ใน cronTab.service.tssrc/crontab/
2way-api (prod)ใช่Announce/Survey/Complaint @ 07:00src/crontab/
recruitment-api (prod)ไม่0ไม่มี

ทำไมไม่มี cron ก็ยัง "ทำงานได้"

recruitment-api เป็น request-driven NestJS API — lifecycle ของธุรกิจถูกออกแบบให้ผูกกับ action ของผู้ใช้ (ทีมสรรหา / ผู้สมัคร / ทีมฐาน) ไม่ใช่ตารางเวลา:

[HTTP POST/PUT] ──► Controller ──► Service

                                      ├─ TypeORM save/update (main / ai)
                                      ├─ axios → workforce-api / vtrc-api
                                      ├─ nodemailer → SMTP (sync ใน request)
                                      └─ PDF/Excel render (sync ใน request)

ไม่มีชั้น "รอถึง 07:00 แล้วค่อยส่ง LINE / sync" แบบที่ 2way-api ทำ — ถ้าต้องการแจ้งเตือนตามเวลา ต้องพึ่งระบบอื่น (เช่น job-scheduler-api, email client ของผู้รับ, หรือ batch นอก repo นี้) ซึ่ง ยังไม่พบ caller จาก repo นี้ ในรอบเอกสารนี้


งานที่ "คล้าย batch" แต่เป็น sync ใน request

ตารางนี้รวม operation ที่ทีมมักเข้าใจผิดว่าเป็น cron — จริง ๆ แล้วถูกเรียกจาก endpoint:

งานTrigger จริงไฟล์หลัก (branch: prod)หมายเหตุ
ส่งอีเมลประกาศผลสอบ/สัมภาษณ์AnnouncementModule confirmannouncement.service.ts + libs/utils/announcementEmailService.tsรันตอน user กด confirm ใน request
ส่งอีเมลสัญญา / export-to-HRMIContractModule update statuscontract.service.ts + contractEmailService.tsไม่มี schedule ส่งซ้ำอัตโนมัติ
ลด remainingManpowerสัญญา status === 'confirm'contract.service.ts:740-763read-modify-write ใน request (ดู CORR-RECRUIT-01 ใน scorecard)
อัปเดต manpower ที่ workforcecreate/update/delete job requestjobRequest.service.ts:948-991HTTP PUT ไป workforce-api
OTP ส่งอีเมลGET /jobList/sent_otp/:emailjobList.service.ts + otpService.util.ts@Public() + sync
PDPA delete cascadeDeleteHistoryModuledeleteHistory.service.tscascade ใน request เดียว
AI compare candidateCandidateModule compare-by-AIcandidate.repositories.ts:1324-1338EXEC SP บน connection ai แบบ sync
Import blacklist จาก ExcelPOST /blacklist/import_blacklistblacklist.controller.ts:20-27@Public() — ไม่ใช่ cron

สิ่งที่ ไม่ พบ (explicit negative evidence)

1) ไม่มี ScheduleModule.forRoot()

recruitment-api/src/app.module.ts (branch: prod):26-66 ลงทะเบียน:

  • ConfigModule
  • TypeORM 4 connection (main, ai, vtrc, workforce)
  • 13 feature module

ไม่มี ScheduleModule ใน imports array — เทียบกับ benefit-api/src/app.module.ts ที่ import ScheduleModule.forRoot() ที่ root

2) ไม่มี provider ชื่อ *TaskService / CronTabService

โครงสร้าง src/modules/ มีแค่ feature module ตามธุรกิจ (jobRequest, candidate, contract, …) — ไม่มี module สำหรับ background task

3) ไม่มี external orchestrator ที่อ้างในโค้ด

  • ไม่พบ import ไป job-scheduler-api
  • ไม่พบ HTTP client เรียก path แบบ /cron หรือ /batch ของระบบอื่นจาก recruitment-api (นอกเหนือ workforce/vtrc ที่เป็น business API)
  • bitbucket-pipelines.yml เป็น CI/CD build+push image — ไม่ เป็น scheduled business job

4) ไม่มี Redis / queue สำหรับ delayed job

package.json ไม่มี ioredis, bull, bullmq, @nestjs/bull — ไม่มี delayed email / retry queue ในตัว service


ผลกระทบเชิง operations เมื่อ "ไม่มี cron"

ด้านผลต่อทีมดูแล
Deploy / restartไม่มี job ค้าง mid-flight จาก scheduler ใน process — ปลอดภัยกว่า repo ที่มี cron ยาว
Horizontal scaleไม่ต้องกังวล leader election ของ @Cron (เพราะไม่มี) — แต่ต้องกังวล race ของ concurrent HTTP (เช่น remainingManpower)
Monitoringไม่มี metric "cron last success" — ต้อง monitor จาก HTTP latency / email SMTP fail ใน request log
Retryถ้าส่งอีเมล fail ตอน confirm สัญญา — ไม่มี auto-retry ตอน 07:00 ต้อง user กดใหม่หรือมี manual path
Nightly cleanupไม่มี job ลบไฟล์ชั่วคราวตามเวลา — มี utility remove-fileByTime เป็น helper ที่เรียกจากโค้ด ไม่ใช่ cron (libs/common/remove-fileByTime.ts)

ความสัมพันธ์กับ health scorecard

ใน 06 Scorecard มิติ Background jobs ได้สถานะเขียว เพราะ:

  1. ไม่มี attack surface ของ unauthenticated cron HTTP trigger (ต่างจากบาง repo ที่เปิด @Public() บน batch endpoint)
  2. ไม่มี SQL string ใน cron ที่รันทุกเช้าโดยไม่มี review
  3. ความเสี่ยงย้ายไปอยู่ที่ sync path แทน (SEC-RECRUIT-02 บน AI compare, CORR-RECRUIT-01 บน manpower)

ถ้าอนาคตจะเพิ่ม cron (เช่น reminder สัมภาษณ์, expire ประกาศอัตโนมัติ) ควร:

  1. เพิ่ม @nestjs/schedule อย่างตั้งใจ + document ในบทนี้
  2. ใส่ leader election หรือรันบน replica เดียว
  3. อย่าเปิด HTTP @Public() สำหรับ manual trigger โดยไม่มี auth
  4. ห้าม raw SQL string concat จาก user input ใน task handler

เปรียบเทียบสั้นกับ sibling services

benefit-api     ── @Cron ×2 (funeral/inheritance HRMI sync)
2way-api        ── @Cron ×3 active (announce/survey/complaint @ 07:00)
                   + PMS notification code มีแต่ @Cron ถูก comment
recruitment-api ── (ว่าง) ไม่มี scheduler ใน process

ข้อสรุปสำหรับผู้อ่าน Volume 6: เมื่อ debug "ทำไมอีเมลประกาศผลไม่ถูกส่งตอนกลางคืน" — คำตอบคือ ระบบไม่ได้ออกแบบให้ส่งตอนกลางคืน; ต้องมีคนกด confirm ใน back-office ช่วงที่มี request ถึง API


เอกสารอ้างอิงภายใน Volume

  • 01 Repository map — โครงสร้างโฟลเดอร์ยืนยันไม่มี crontab/
  • 02 Core pipeline — ทุก stage เป็น HTTP-driven
  • 03 Persistence — connection / entity (ไม่มี job table สำหรับ scheduler)
  • 04 Auth + integrations — email/SMTP ถูกเรียกจาก service layer
  • 06 Scorecard — debt ที่เกี่ยวกับ sync path แทน cron path

ไป บท 6 Scorecard