Jobs & Cache · infrastructure/jobs

Production-ready adapter

BullMQ,
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.

queues.ts
 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_URLrequired

    required for the jobs subsystem

  • JOBS_REDIS_URLoptional

    dedicated jobs Redis; falls back to REDIS_URL

Where it lives

  • apps/server/src/infrastructure/jobs/queues.ts
  • apps/server/src/infrastructure/jobs/redis-connection.ts
  • apps/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.