Skip to main content

All Cron Scheduler Jobs

Overview

The cron-scheduler profile is a single process that bundles 10 timed jobs and 4 consumers (mbox handoff/callback, booking notification/event).

Design principle: most crons don't do the heavy work themselves — they only figure out "what's due now" and publish jobs onto a queue for the real consumer to handle. That lets heavy work scale independently of the timer, and overlapping cron fires across multiple replicas don't produce duplicate effects, because claiming work is atomic at the DB/Redis level.

It uses robfig/cron, running on the server's local time just like the original NestJS @Cron decorators (per-rule Asia/Bangkok timezone handling lives inside ScheduledTriggerScannerService.processRule).

Business Flow

All 10 cron jobs

CronTable/Data SourceWhat it doesDocs
*/1 * * * * scheduledTrigger.Runtrigger_rule (source_type='scheduled')Finds due rules (per-rule timezone math) and publishes scheduled_trigger_firetrigger-engine
*/1 * * * * scheduledAction.Runscheduled_actionRecovers rows stuck for 5 minutes, claims 500 rows with FOR UPDATE SKIP LOCKED, publishes scheduled_action_firescheduled-action
0 * * * * campaignStat.RunRedis CAMPAIGN_STAT_DIRTY:*Finds campaigns with new data and publishes calculate_campaign_statcampaign-stat-calculation
0 * * * * richMenuStat.RunRedis RICH_MENU_STAT_DIRTY:*Finds rich menus with new data and publishes calculate_rich_menu_stat_itemrich-menu-stat-calculation
*/5 * * * * autoResponseSync.Runline_oa + auto_responseRebuilds the Redis keyword hash for every active OA (a broken OA uses continue, not return)auto-response
*/1 * * * * mboxTimeout.RunRedis sorted set agent_sessionsWarns (stage 1) and closes (stage 2) agent sessions that have timed outmbox-agent-handoff
*/1 * * * * bookingReminder.Runappointment.booking + journeyFinds bookings due for a reminder and publishes booking_notificationbooking-notification
*/1 * * * * bookingNoShow.Runappointment.booking + journeyFinds bookings past time plus a grace period and marks them no-showbooking-notification
*/1 * * * * campaignSchedule.RunRedis tick keyPublishes process_campaign once per minute (deduped across replicas with SET NX)campaign-schedule-dispatch
0 3 * * * loyaltyTier.Runloyalty.program / tier / accountRecalculates membership tiers platform-wide (the only path that can demote)loyalty-tier-recalculation

The 4 consumers that run alongside them

Startup sequence

  1. runCronScheduler creates the mq.Client and asserts the topology
  2. Assembles every service (mbox handoff/callback, booking notification/event, all 10 scanners), sharing the same pgx pool / RedisService / mq publisher / Mbox REST client
  3. cron.New() then AddFunc for each job by its expression; a registration error stops the profile immediately
  4. c.Start(), with context.AfterFunc(ctx, c.Stop) wired up for a clean stop on shutdown
  5. Registers all 4 consumers on the mq.Registrar and runs them as goroutines

Key Files & Functions

  • cmd/worker/main.gorunCronScheduler(ctx, a) (defines the jobs []cronJob list of 10)
  • internal/cronscheduler/ — one file per 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() (converts pgx rows into []map[string]any)
  • internal/cronscheduler/health.go — the profile's health surface
  • Tests: campaign_schedule_scanner_test.go, loyalty_tier_test.go

Connections to Other Services

  • PostgreSQL — every scanner except the campaign/rich-menu stat ones (which read Redis)
  • Redis — dirty keys for the stat scanners, tick dedup for campaign schedule, agent_sessions for mbox timeout, and the auto-response keyword hash
  • RabbitMQ — publishes work to destination queues and consumes 4 queues
  • Mbox REST API and LINE API — via the mbox / booking services
  • ENV: ENABLE_CRON_SCANNING (app-level toggle), CRON_SCHEDULER_PORT (default 3003)