Skip to content

Background Jobs & Cron

Arsitektur queue

Sistem tidak memakai Bull/Redis (meskipun bull ada di package.json). Pekerjaan asinkron memakai DB-backed queue (tabel Jobs) + child process lewat job-runner.js. Tidak ada backpressure — job di-spawn fire-and-forget.

Mekanisme job-runner.js

job-runner.js adalah loader skrip dinamis (bukan daemon worker yang berjalan terus):

bash
node job-runner <scriptName> [arg]
# resolve: require(`${__dirname}/cron/${scriptName}`)
  • argv[2] = path di bawah cron/ (dengan/tanpa .js).
  • Skrip yang di-require langsung berjalan saat dimuat (kebanyakan memanggil runProcess()).
  • Argumen tambahan diteruskan via process.argv[3+].

Pola pemanggilan:

bash
# via npm
npm run cron:jobs:reset-sending-quota   # -> node job-runner job-reset-quota-mail

# langsung
node job-runner invoices/recurring-invoice/job-recurring-invoice

# dengan job ID (arg ke-4)
node job-runner.js job-send-mail-daily-report 123

Pola producer → consumer

  • Producer menulis baris Jobs (status on-queue) via repositories/job.repository.js, lalu men-spawn consumer via helpers/cp.helper.js.
  • Consumer (cron/job-*.js) mem-poll Jobs berdasarkan jobType + status: 'on-queue', set processing, proses, lalu done/error.

Lifecycle API (repositories/job.repository.js)

FungsiAksi
register()Buat job on-queue
getByType() / getAllByTypeLike()Dequeue FIFO
jobProcessing()Set processing
jobDone(id, isDone, error)Set done/error + params3
deleteOlderThan()Housekeeping

Scheduler: eksternal, bukan in-process

  • server.js memanggil cron.runnerJob() saat startup, tetapi cron/scheduledFunctions/runnerJob.js adalah stub kosong (semua CronJob.schedule di-comment).
  • Semua penjadwalan dilakukan eksternal (crontab di VPS menjalankan npm run cron:*).

Implikasi handover

Jadwal cron tidak ada di repo. Saat handover, periksa crontab/scheduler di server production untuk mengetahui job apa yang berjalan dan pada jam berapa. PM2 hanya mengawasi server HTTP — kegagalan cron tidak muncul di log PM2.

Daftar cron (npm scripts)

Jadwal di bawah berasal dari komentar di file (perkiraan konfigurasi ops), bukan definisi live.

npm scriptJadwal (perkiraan)TujuanFile
cron:invoices:recurring0 0 * * *Cari invoice jatuh tempo 14 hari; buat invoice/subscription berikutnya; enqueue emailcron/invoices/recurring-invoice/job-recurring-invoice.js
cron:invoices:recurring:notif-user0 8 * * *Kirim email PDF estimate Zoho.../job-recurring-invoice__notif-user.js
cron:invoices:recurring:notif-user--reminder0 8 * * *Register reminder H-1/3/5/0 & H+1..3.../job-recurring-invoice__notif-user-reminder.js
cron:invoices:recurring:notif-user--reminder:sendersetelah reminderKirim email reminder.../job-recurring-invoice__notif-user-reminder__sender.js
cron:invoices:recurring:checker-daily-mail:sendersetelah recurringEmail checker admin.../job-recurring-invoice__checker-daily-mail__sender.js
cron:invoices:paid-over-periodeharianExpire trial/sub; tandai invoice overdue/cancelled; suspend relay.../paid-over-periode-invoice/job-paid-over-periode-invoice.js
cron:invoices:paid-over-periode:expired-trial:senderpollKirim email trial expired.../job-trial-package-is-expired__sender.js
cron:jobs:reset-sending-quota58 23 * * *Reset kuota bulanan; enqueue over-quota billingcron/job-reset-quota-mail.js
cron:jobs:deleteperiodikHapus job done >7 haricron/job-delete-three-days-old-jobs.js
cron:jobs:relay-housekeepingperiodikHapus relay Zimbra suspended >1 bulancron/job-relay-account-housekeeping.js
cron:jobs:reminder-locked-relay30 * * * *Email reminder relay terkunci spamcron/job-reminder-locked-relay-account.js
cron:sync-attachment-zmtaperiodikSinkron batas attachment per domain ke ZMTAcron/sync-domain-zmta.js
cron:jobs:daily-reports15 0 * * *Build CSV harian dari ES, upload S3, kirim emailcron/scheduledFunctions/jobs/generateCSVScheduledJob.js
cron:jobs:daily-failed45 17 * * *Digest delivery gagal, kirim emailcron/scheduledFunctions/jobs/dailyFailedReport.js
cron:auth-zohosebelum token expiryRefresh OAuth token Zoho ke DB configcron/job-update-access-token-zoho.js
cron:add-detail-reportharianAgregasi pemakaian mail ES → tViewcron/job-add-detail-reports.js
cron:quota-checkerperiodikCari kuota ≥80/90/100%; enqueue notifcron/job-notif-quota-checker.js
cron:overquota:reminder1 0 * * *Register reminder/suspend invoice over-quotacron/overquota/job-overquota-reminder-invoice.js
cron:overquota:reminder-sender1 8 * * *Kirim email reminder over-quotacron/overquota/job-overquota-reminder-invoice-sender.js
cron:overquota:generate-billing0 0 * * *Proses job; buat billing Zoho/Xenditcron/overquota/job-overquota-generate-billing.js
cron:overquota:send-billing0 8 * * *Email proforma over-quotacron/overquota/job-overquota-send-billing.js

Cron tambahan (tidak di package.json, mungkin dijadwalkan manual)

TujuanFile
Register notif suspend customer recurringcron/job-notif-suspend.jsjob-notif-suspend-sender.js
Tandai invoice overduecron/set-overdue-package.js
Bersihkan JWT blacklist kedaluwarsacron/remove-blacklist-token.js
Token Zoho via browser (legacy)cron/generate-token-zoho.js
Email konfirmasi pembayaran over-quotacron/overquota/job-overquota-send-invoice.js
Registrasi kontak MailWizzcron/mailwizz/job-register-contact-mailwizz.js

Worker event-driven (di-spawn dari handler HTTP)

WorkerDipicu dariFile
job-send-mail-invoiceCallback Xendit, manual payment, recurringcron/job-send-mail-invoice.js
job-send-mail-signupSign-upcron/job-send-mail-signup.js
job-send-mail-add-domainSetup domaincron/job-send-mail-add-domain.js
job-notif-quotaQuota checker croncron/job-notif-quota.js
job-update-file-cfPackage CRUDcron/job-update-file-cf.js
sync-domain-zmtaCallback Xenditcron/sync-domain-zmta.js

/automation/

Folder automation/ berisi satu TestCafe spec (zoho-auth.testcafe-spec.js) untuk otomasi login/consent OAuth Zoho (legacy). Bukan bagian infrastruktur job production. Dijalankan via npm run test:cafe / test:cafe:headless.