Skip to main content

งานตามเวลา (Cron Scheduler) ทั้งหมด

ภาพรวม

Profile cron-scheduler เป็น process ที่รวม งานตามเวลา 10 ตัว และ consumer 4 ตัว (mbox handoff/callback, booking notification/event) ไว้ด้วยกัน

หลักการออกแบบ: cron ส่วนใหญ่ ไม่ทำงานหนักเอง แต่ทำหน้าที่ "หาว่ามีอะไรถึงเวลาแล้วบ้าง" แล้ว publish งานเข้า queue ให้ consumer ตัวจริงทำต่อ — ทำให้ scale งานหนักแยกจากตัวจับเวลาได้ และ cron ที่ยิงซ้อนกัน (หลาย replica) ไม่ทำให้เกิดผลซ้ำ เพราะการจองงานเป็น atomic ที่ระดับ DB/Redis

ใช้ robfig/cron โดยรันตาม local time ของ server เหมือน @Cron ของ NestJS เดิม (การจัดการ timezone Asia/Bangkok รายกฎอยู่ภายใน ScheduledTriggerScannerService.processRule)

Business Flow

ตาราง cron ทั้ง 10

Cronตาราง/แหล่งข้อมูลทำอะไรเอกสาร
*/1 * * * * scheduledTrigger.Runtrigger_rule (source_type='scheduled')หากฎที่ถึงเวลายิง (คำนวณ timezone รายกฎ) แล้ว publish scheduled_trigger_firetrigger-engine
*/1 * * * * scheduledAction.Runscheduled_actionกู้แถวค้าง 5 นาที, claim 500 แถวด้วย FOR UPDATE SKIP LOCKED, publish scheduled_action_firescheduled-action
0 * * * * campaignStat.RunRedis CAMPAIGN_STAT_DIRTY:*หา campaign ที่มีข้อมูลใหม่ publish calculate_campaign_statcampaign-stat-calculation
0 * * * * richMenuStat.RunRedis RICH_MENU_STAT_DIRTY:*หา rich menu ที่มีข้อมูลใหม่ publish calculate_rich_menu_stat_itemrich-menu-stat-calculation
*/5 * * * * autoResponseSync.Runline_oa + auto_responserebuild Redis hash คีย์เวิร์ดของทุก OA ที่ active (OA ที่พังใช้ continue ไม่ return)auto-response
*/1 * * * * mboxTimeout.RunRedis sorted set agent_sessionsเตือน (stage 1) และปิด session เจ้าหน้าที่ที่หมดเวลา (stage 2)mbox-agent-handoff
*/1 * * * * bookingReminder.Runappointment.booking + journeyหาการจองที่ถึงเวลาเตือน publish booking_notificationbooking-notification
*/1 * * * * bookingNoShow.Runappointment.booking + journeyหาการจองที่เลยเวลา + grace period แล้ว mark no-showbooking-notification
*/1 * * * * campaignSchedule.RunRedis tick keypublish process_campaign 1 ใบ/นาที (dedup ข้าม replica ด้วย SET NX)campaign-schedule-dispatch
0 3 * * * loyaltyTier.Runloyalty.program / tier / accountคำนวณระดับสมาชิกใหม่ทั้งแพลตฟอร์ม (ตัวเดียวที่ลดระดับได้)loyalty-tier-recalculation

Consumer 4 ตัวที่รันร่วมกัน

ลำดับการทำงาน

  1. runCronScheduler สร้าง mq.Client, assert topology
  2. ประกอบ service ทั้งหมด (mbox handoff/callback, booking notification/event, scanner 10 ตัว) โดยแชร์ pgx pool / RedisService / mq publisher / Mbox REST client เดียวกัน
  3. cron.New() แล้ว AddFunc ทีละ job ตาม expression; error ตอน register จะทำให้ profile หยุดทันที
  4. c.Start() และผูก context.AfterFunc(ctx, c.Stop) เพื่อหยุดอย่างสะอาดตอน shutdown
  5. register consumer ทั้ง 4 ลง mq.Registrar แล้วรันเป็น goroutine

ไฟล์และฟังก์ชันหลัก

  • cmd/worker/main.gorunCronScheduler(ctx, a) (นิยาม jobs []cronJob ทั้ง 10 รายการ)
  • internal/cronscheduler/ — ไฟล์ละ 1 scanner: scheduled_trigger_scanner.go, scheduled_action_scanner.go, campaign_stat_scanner.go, rich_menu_stat_scanner.go, auto_response_sync.go, mbox_timeout.go, booking_reminder.go, booking_noshow.go, campaign_schedule_scanner.go, loyalty_tier.go
  • internal/cronscheduler/helpers.gocollectRows() (แปลง pgx rows ให้เป็น []map[string]any)
  • internal/cronscheduler/health.go — health surface ของ profile
  • ทดสอบ: campaign_schedule_scanner_test.go, loyalty_tier_test.go

จุดเชื่อมต่อกับ Service อื่น

  • PostgreSQL — ทุก scanner ยกเว้น campaign/rich-menu stat (ซึ่งอ่าน Redis)
  • Redis — dirty key ของ stat scanner, tick dedup ของ campaign schedule, agent_sessions ของ mbox timeout, hash คีย์เวิร์ดของ auto-response
  • RabbitMQ — publish งานเข้า queue ปลายทาง และ consume 4 queue
  • Mbox REST API และ LINE API — ผ่าน mbox / booking service
  • ENV: ENABLE_CRON_SCANNING (toggle ระดับแอป), CRON_SCHEDULER_PORT (default 3003)