Cron Catalog
A reference of the scheduled jobs that drive Prism's queues. There are ~88 .js files directly under crons/ plus three subfolders, alongside cron-registering modules in processLibrary/, commonFunctions/, and a couple of controllers/ (order ingestion). All self-register with node-cron when require()d at startup (see Request Lifecycle). This catalog covers the operationally significant crons grouped by function; it is not an exhaustive per-file dump.
Validation legend
| Symbol |
Meaning |
| ✅ |
Verified against source in this review |
| 📄 |
From the architecture map (map-04-crons-queues) |
| 💻 |
Behaviour confirmed by reading the file |
| ♻️ |
Legacy / superseded but still running |
| ⚰️ |
Commented out in index.js (not active) |
| ⚠️ |
Tech-debt / operational risk |
Schedules are node-cron expressions (min hour day month weekday), IST server time.
1. Ingestion
| File |
Purpose |
Schedule |
Queue / collections |
controllers/petpoojaOrderIngestion.js |
Ingest PetPooja orders |
internal schedule 📄 |
→ orders, crm_queue, crm_points_allocation_queue |
controllers/uengageOrderIngestion.js |
Ingest uEngage orders |
internal schedule 📄 |
→ same |
commonFunctions/processCommonIngestion.js |
Common ingestion (Swiggy/Zomato/POS/dashboard); validate, enrich, insert; trigger points |
on demand + drain 📄 |
→ orders, crm_queue, crm_points_allocation_queue |
deleteCrmQueue.js |
Delete old crm_queue: status=1 completed, and source=6 non-terminal events (keep only "Closed") |
0 2 */2 * * (2 AM, every 2 days) ✅📄 |
W: crm_queue (delete) |
2. Campaign / Journey dispatch
| File |
Purpose |
Schedule |
Queue / collections |
autoCampaign.js |
Set auto_campaign flag per parent business from campaign_journeys config |
47 12 * * * (12:47 PM) 📄 |
R: business_configs, campaign_journeys / W: business_configs |
processAutomatedCampaigns.js |
Iterate enabled campaign_journeys, queue via automatedCampaignQueueNew |
0 22 * * * (10 PM) 📄 |
R: campaign_journeys → channel queues |
abandonCartCron.js |
Unshipped carts (addo_orders status=0, total>1) → build SMS/WhatsApp, queue |
*/5 * * * * (5 min) 📄 |
R: MySQL addo_orders / W: sms_queue_*, whatsapp_queue_*, auto_campaign_roi |
processLibrary/uengageProcess.js |
Main journey/campaign orchestrator (~89 KB); audience, wallet, rate limits |
⚰️ commented in index.js 📄 |
→ channel queues + auto_campaign_roi |
processLibrary/processCampaign.js |
Legacy campaign executor (~70 KB) |
📄 ♻️ |
→ channel queues |
processLibrary/npsRequest.js |
NPS survey sends + response tracking |
internal 📄 |
→ sms_queue_*, whatsapp_queue_* |
campaignOrderSummary.js |
Per-campaign order summary |
internal 📄 |
campaign metrics |
3. Loyalty / Points
| File |
Purpose |
Schedule |
Queue / collections |
crmPointsAllocationQueueCron.js |
MySQL points queue drain; types uen_order, order_reward, welcome_point, refer_earn; 5 retries / 15-min backoff, LIMIT 5000 |
*/2 * * * * (2 min) ✅💻 |
R/W: MySQL crm_points_allocation_queue, wallet tables / R/W: Mongo orders, customers |
pointAllocation.js ♻️ |
Legacy MongoDB points queue (loyalty_points_allocate status=0) |
*/1 * * * * (1 min) 📄 |
R/W: loyalty_points_allocate + MySQL wallet |
loyalty_milestone_downgrade.js |
Downgrade one tier if lastOrderDate ≥ downgrade_days |
0 2 * * * (2 AM) 📄 |
R: MySQL wallet_rules, loyalty_milestones / W: customers, addo_contacts_mapping, milestone_logs |
loyaltyCustomerPointsCron.js |
Top spenders / expiring-soon / expired counts → Redis wallet_{parent}__YYYY-MM-DD |
35 2 * * * (2:35 AM) 📄 |
R: MySQL wallet, customers / W: Redis |
rewardsCrons/birthdayAnniversaryRewards.js |
Birthday/anniversary reward grants |
internal 📄 |
wallet + channel queues |
rewardsCrons/recurringRewards.js |
Recurring/scheduled reward grants |
internal 📄 |
wallet + channel queues |
4. RFM / Segments
| File |
Purpose |
Schedule |
Queue / collections |
rfmSegments.js |
R/F/M score over 90 days → segment (new_customers, promising, regular, champions, need_attention, at_risk, lost) |
0 3 * * * (3 AM) 📄 |
R: orders, customers, wallet_rules / W: rfm_metrics_tmp, rfm_job_log |
customerInsightsCron.js |
Advanced segmentation (mobile validity, visited_days, time_of_day, order_amount) |
TBD 📄 |
R: customers, orders, MySQL wallet / W: segment_counts |
segments_count.js |
Channel-reachable counts: SMS (dnd_flag=0), WhatsApp (optin=1), Push (FCM tokens) |
45 16 * * * (4:45 PM) 📄 |
R: customers_*, fcm_tokens_* / W: segment_counts, business_configs |
returningCustomerCron.js |
Returning-customer count → Redis customers_{parent}__{MM-YYYY} |
0 2 * * * (2 AM) 📄 |
R: customers / W: Redis |
dedupCustomers.js |
Dedup customers by mobileNo (canonical by LTO/LTV/_id); has ~4 h force-close fallback |
0 1 * * * (1 AM) 📄 |
R/W: customers, customers_outlets |
5. Analytics / MIS
| File |
Purpose |
Schedule |
Queue / collections |
processLibrary/aggregationProcess.js |
Orders ETL → 14 daily-aggregate collections (IST date math) |
⚰️ commented in index.js 📄 |
W: orders_by_day_business, daily_summary_by_parent, … |
processLibrary/campaignAggregation.js |
Sends by campaign_id/status: sent/delivered/failed/bounced |
internal 📄 |
W: campaign_aggregation |
processLibrary/campaignMis.js |
Campaign ROI / conversions / revenue |
internal 📄 |
W: campaign_mis |
processLibrary/dashboardMIS.js |
Dashboard aggregates: orders, revenue, AOV, customer counts |
⚰️ dailyMisReport commented in index.js 📄 |
W: dashboard_mis |
processLibrary/segmentCountV2.js / getOnlySegmentCount.js |
Multi-field segment counting |
helper 📄 |
segment count results |
ROI subfolder — crons/autoCampaignRoiCrons/ ✅
Attribution jobs that credit revenue back to the campaign/journey that drove it:
| File |
Purpose |
autoCampaignRoi.js |
Core auto-campaign ROI attribution |
abandonCartRoi.js |
Abandoned-cart recovery ROI |
lostCustomersRoi.js |
Win-back / lost-customer ROI |
referEarnRoi.js |
Refer-and-earn ROI |
welcomeMsgRoi.js |
Welcome-message ROI |
roiSnapshotBackfill.js |
Backfill historical ROI snapshots |
6. Reports / Email
| File |
Purpose |
Schedule |
Queue / collections |
dripCampaignCron.js |
Excel reports: active/inactive/digital-bill/auto-campaign/feedback users |
0 12 * * 1 (Mon 12 PM) 📄 |
R: business_configs, wallet_transactions, digital_bill_mis, feedback_mis / W: Excel |
monthly_whatsapp_report.js |
Monthly WhatsApp usage report |
monthly 📄 |
R: whatsapp_queue_* history |
7. Cleanup / Maintenance
| File |
Purpose |
Schedule |
Queue / collections |
deleteCrmQueue.js |
Prune crm_queue (see §1) |
0 2 */2 * * 📄 |
W: crm_queue |
dedupCustomers.js |
Dedup customers (see §4) |
0 1 * * * 📄 |
customers, customers_outlets |
updationCrons/update_existing_data_addo_business.js ✅ |
One-off/periodic backfill on addo_business |
internal |
MySQL addo_business |
⚠️ Date-partitioned queue collections (sms_queue_YYYYMMDD, push_noti_queue_YYYYMMDD, whatsapp_queue_YYYYMMDD) accumulate over time. deleteCrmQueue prunes crm_queue, but there is no single owner of stale channel-queue-collection archival. See Technical Debt.
8. WhatsApp / SMS / Push consumers
| File |
Purpose |
Schedule |
Queue / collections |
smsQueueCron.js |
Drain sms_queue_* (processed=false, execution_time<=now), batches of 8000 → sendAutoCampaignSms |
*/3 * * * * (3 min) ✅💻 |
R/W: sms_queue_*, sms_cron_status |
sendWhatsappMessageCron.js |
Drain marketing WhatsApp (process_status=0, type absent) → whatsappMsgProcess |
~3 s poll ⚠️ 📄 |
R/W: whatsapp_queue_*, whatsapp_cron_status |
sendWhatsappTransactionalCron.js |
Drain transactional WhatsApp (process_status=0, type present) |
~1 s poll ⚠️ 📄 |
R/W: whatsapp_queue_*, whatsapp_cron_status |
pushQueueCron.js |
Group push_noti_queue_* (processed=false) → Firebase via processNotiQueue |
*/5 * * * * (5 min) 📄 |
R/W: push_noti_queue_*, push_cron_status |
9. ⚠️ Tech-debt hotspots in the cron layer
Cross-referenced in Technical Debt.
- ⚠️ Duplicate campaign-queue implementations —
automatedCampaignQueue.js (legacy, ~73 KB) and automatedCampaignQueueNew.js (~94 KB) coexist; both write the same channel queues. Consolidate to one versioned builder.
- ⚠️ Dual points queues — MongoDB
loyalty_points_allocate (pointAllocation.js, 1 min) vs MySQL crm_points_allocation_queue (2 min, with retries). Deprecate the Mongo path.
- ⚠️ 1-second polling throttle risk —
sendWhatsappTransactionalCron polls every ~1 s and pushes to Gupshup/Facebook with no rate limiting or backoff; a spike risks provider throttle/ban and thundering-herd DB load.
- ⚠️ Non-atomic MySQL + Mongo points —
crmPointsAllocationQueueCron mutates MySQL wallet tables and Mongo customers/orders without a distributed transaction; partial-failure windows exist. Enforce idempotency / a saga.
- ⚠️ Missing WhatsApp delivery-receipt handler — sends land at
process_status=3 ("sent, pending webhook") but there is no cron/consumer processing Gupshup/Facebook delivery receipts, so delivered/read state is never reconciled.
- ⚠️ Reactive stuck-cron detection — overlap locks (
*_cron_status, cron_statuses) only email after ~20 min; only dedupCustomers force-closes (~4 h). No circuit breaker, no auto-restart, no DLQ.
- ⚠️ Inconsistent status fields —
processed bool (SMS/Push), process_status int (WhatsApp), status string (MySQL points), status 0/1/-1 (legacy Mongo points). Unify.
- ⚠️ Firebase app per batch —
processNotiQueue calls admin.initializeApp(..., appName + Date.now()) per group; potential memory leak. Pool per parent business.