Background Jobs
19 jobs total — 14 QStash scheduled + 4 QStash triggered + 1 GitHub Actions cron.
All scheduled and event-driven jobs run on QStash (HTTP → Next.js API routes
hosted in
apps/admin, served from admin.theroyalglow.in/api/jobs/*). The
single exception is the pprd branch reset (Job 5), a Neon control-plane op on
GitHub Actions cron. Every job pings a BetterStack heartbeat on success.@rgss/db query functions. The single
exception is the pprd branch reset (Job 5), which is a Neon control-plane op and
runs on GitHub Actions cron.
pg_cron is not used. The 6 DB-maintenance jobs were originally planned on
pg_cron, but the free-tier prod Neon compute scales to zero after ~5 min idle
and pg_cron only fires while the compute is awake — the late-night windows
(11:30 PM–2:30 AM IST) would silently never run. QStash POSTs an endpoint that
wakes the compute, so the jobs run reliably at ₹0. The job SQL was ported
verbatim into
packages/db/src/queries/jobs.ts.Where jobs run
- Tab Title
- Tab Title
Upstash HTTP queue → Next.js API routes in
apps/admin. Use for ALL scheduled
and triggered jobs (DB maintenance + external services).Every QStash job calls a POST /api/jobs/... route and is auto-retried (3x,
exponential backoff) on a non-2xx response. Every job pings a BetterStack
heartbeat on success so silent failures get detected. The /api/jobs/* routes are
served from admin.theroyalglow.in/api/jobs/*; QStash schedules are registered
from the admin deploy.All schedules are in UTC; the salon operates IST (UTC+5:30).
Not jobs (synchronous / external)
Three time-critical actions deliberately run in-request, not as jobs:- Invoice email + PDF — fired immediately when the receptionist marks payment received.
- Gems-earned push — fired in the same request as invoice completion.
- Re-engagement email — handled inside Brevo automations (marketing), not counted here.
Job inventory
- Tab Title
- Tab Title
- Tab Title
These run in the early IST hours when traffic is zero. Jobs 1–4, 6 and 7 run on
QStash (each POSTs its
/api/jobs/... route, which runs the idempotent SQL via
a @rgss/db query function) — not pg_cron. Job 5 runs via GitHub Actions cron
(Neon branch reset) plus SQL anonymisation.