Jobs & Cache · infrastructure/jobs
Production-ready adapterBullMQ,
typed and catalogued.
Real SaaS work happens off the request path. UseDeploy ships a BullMQ setup with a single source-of-truth queue catalog, typed job payloads, and the ioredis connection quirks that trip up hand-rolled setups already handled.
One catalog, typed payloads
Queues are declared once in QUEUE_NAMES so the worker bootstrap and the Bull Board mount iterate a single source of truth. Each queue has a typed payload interface, so a misnamed key surfaces at compile time instead of at runtime in the worker.
1 export const QUEUE_NAMES = {
2 emails: 'emails',
3 webhooksOutgoing: 'webhooks-outgoing',
4 billingWebhooksRetry: 'billing-webhooks-retry',
5 accountDeletions: 'account-deletions',
6 dataExports: 'data-exports',
7 usagePeriodRollover: 'usage-period-rollover',
8 } as const;
What ships
Centralized connection
createJobsConnection resolves JOBS_REDIS_URL then REDIS_URL and applies maxRetriesPerRequest: null — the setting BullMQ demands so blocking commands never time out mid-poll.
Typed job data
EmailJobData, DataExportJobData and friends are shared by producers and consumers, so payload drift is a type error.
Bull Board
A mounted dashboard lets you inspect, retry and drain queues in dev and ops.
Empty-URL guard
The URL resolver trims before it checks, so a stray JOBS_REDIS_URL= placeholder falls back to REDIS_URL instead of crash-looping the worker.
Configuration reference
Environment variables
REDIS_URLrequiredrequired for the jobs subsystem
JOBS_REDIS_URLoptionaldedicated jobs Redis; falls back to REDIS_URL
Where it lives
apps/server/src/infrastructure/jobs/queues.tsapps/server/src/infrastructure/jobs/redis-connection.tsapps/server/src/infrastructure/jobs/bull-board.ts
Move the slow work off the request.
Start with a typed queue catalog, Redis-backed workers and a dashboard already wired.