BullMQ
Use this skill when work touches BullMQ Redis queues, workers, flows, retries/scheduling, NestJS BullMQ, or Pro-vs-OSS decisions.
Workflow
- Inspect the local BullMQ surface before changing code:
- Package versions for
bullmq,@nestjs/bullmqif present, Redis clients (ioredis,redis), Node/Bun, and TypeScript. - Connection shape: options object vs shared client vs adapters (
createNodeRedisClient,createBunRedisClient);prefix; Redis DB index. - Producers (
Queue,FlowProducer) vs consumers (Worker); process isolation (inline vs sandboxed file / worker threads). - Default job options, schedulers, rate limits, dedupe usage, Nest module registration if present.
- Package versions for
- Refresh current official docs when the task depends on latest APIs, version drift, Pro features, adapters, or Nest wrappers. Start from source-map.md.
- Route the work to the focused references:
- Setup, Redis connections, Queue, Worker, QueueEvents: setup-connections.md.
- Job lifecycle and JobsOptions: jobs-options.md.
- Parent-child flows / FlowProducer: flows.md.
- Retries, delays, job schedulers, rate limits, dedupe: retries-scheduling-limits.md.
- Ops, testing, NestJS, Pro vs OSS, polyglot: production-ops-integrations.md.
- Preserve the repository's existing connection factories, Nest modules, and deployment topology unless the user explicitly asks for a migration.
- Verify behavior at the narrowest useful boundary (processor unit), then queue/worker integration.
Core Judgment
- Treat Redis as shared infrastructure. Reuse connection options or factories deliberately; Workers and QueueEvents still duplicate connections for blocking commands, so the client must support
duplicate(). - Attach
errorlisteners onQueue,Worker,QueueEvents, andFlowProducer. Unhandled connection errors crash Node. - Design processors as idempotent. Jobs can retry, stall after lock loss, or run more than once—side effects need safe keys or transactional checks.
- Set
attemptsandbackoffintentionally. ThrowUnrecoverableErrorfor poison/permanent failures; throwErrorobjects (not strings) from processors. - Prefer
FlowProducerfor parent-child dependency graphs. Do not hand-roll “wait for children” with races across queues. Flow job opts omitrepeat,deduplication, anddebounce. Pick child failure opts deliberately (failParentOnFailure,ignoreDependencyOnFailure,removeDependencyOnFailure,continueParentOnFailure). - Rate limiting is global per queue across workers. Do not resurrect removed patterns (
QueueScheduler, pre-v3 groupKey rate limits) on BullMQ 5.x. Group rate limits are Pro-only. - Deduplication needs a stable
deduplication.id. Choose simple vs throttle (ttl) vs debounce (extend/replace+ delay) vskeepLastIfActivefor the product semantics. - Priority: lower number wins among prioritized jobs (
1..2097151); unset/0is unprioritized and is processed before any prioritized job. - Tune
removeOnComplete/removeOnFail(age or count keep policies). Unbounded completed/failed sets grow Redis without bound. Never use iorediskeyPrefix; use BullMQprefix(brace hash tags on Cluster). - Close workers gracefully on shutdown (
worker.close()). Killing processes mid-lock causes stalls and duplicate work unless ops expect that window. - Prefer
queue.upsertJobSchedulerover legacyrepeat/QueueSchedulerfor cron/interval factories. Prefer@nestjs/bullmqover legacy@nestjs/bull. - Do not recommend BullMQ Pro-only APIs (groups, group rate limits, batches, observables) unless the project already uses Pro. Call the boundary out explicitly.
- Keep processors thin and non-blocking on the event loop. Use sandboxed processors /
useWorkerThreadswhen CPU-heavy or crash-isolating work is required. Jobdatais plaintext in Redis — avoid secrets or encrypt fields.
Verification
Prefer repository-owned commands. For meaningful BullMQ changes, cover the relevant subset:
- Typecheck Queue/Worker/FlowProducer options, job
data/returnvaluetypes, and Nest injection tokens if used. - Unit-test processor success, retryable failure,
UnrecoverableError, and progress updates in isolation. - Integration test against Redis: add → process → complete/fail; assert job state transitions.
- Delayed/scheduler tests with short intervals; assert no duplicate schedules after redeploy when that matters (
upsertJobScheduler). - Rate-limit / dedupe tests: assert ignored/replaced/deferred behavior and any
deduplicatedevents. - Flow tests: children complete before parent; parent reads
getChildrenValues; child failure policy (failParentOnFailure/ignoreDependencyOnFailure/removeDependencyOnFailure/continueParentOnFailure) matches product intent. - Stall/lock smoke when changing
lockDuration,stalledInterval,maxStalledCount, or long-running processors. - Graceful-shutdown smoke: SIGTERM/
closepath finishes in-flight work without unexpected orphaned locks beyond the stall window. - NestJS module smoke: queue registration,
WorkerHostprocessors, and FlowProducer injection when Nest is in play. - Redis growth check when changing retention (
removeOnComplete/removeOnFail) or adding high-throughput queues.
Report which checks ran, which did not, and any Pro/OSS or package-version assumptions that remain.