> nestjs-bullmq
Standard workflow for BullMQ jobs in NestJS. Use for: queue processors, redis-throttler, Upstash limits, idle polling (10s), stalled jobs, and retention. Triggers on: bullmq, processors, registerQueue, drainDelay, stalledInterval, removeOnComplete, Redis outages, or failing background tasks. (triggers: **/*.processor.ts, **/*.module.ts, **/bull-queue.constants.ts, **/redis-throttler*.ts, queue, background job, worker, processor, bullmq, drainDelay, stalledInterval, removeOnComplete, redis limit,
curl "https://skillshub.wtf/HoangNguyen0403/agent-skills-standard/nestjs-bullmq?format=md"NestJS BullMQ Implementation
Priority: P0 (Critical)
Guidelines
- Set idle polling: Add
drainDelay+stalledInterval+maxStalledCountto every@Processor. DefaultdrainDelay(5 ms) burns 570M Redis commands/day at idle. See patterns.md. - Throttle worker error logs: BullMQ workers emit raw unhandled ReplyErrors on Redis failure (e.g. Upstash rate limits). Always extend
BaseProcessorinstead ofWorkerHostto rate-limit these logs. See patterns.md. - Set job retention: Add
removeOnComplete,removeOnFail,attempts,backoffto everyBullModule.registerQueue. See patterns.md. - Use shared constants: All numeric options live in
src/common/constants/bull-queue.constants.ts. Queue/job names go in{feature}.constants.ts. Never inline magic numbers. - Wrap every
queue.add(): Persist DB record first, then enqueue inside try-catch. Redis errors must not surface as 500s. See patterns.md. - Throttler fail-open:
RedisThrottlerStorage.increment()must catch all Redis errors and return a pass-through record. A Redis blip must not kill all HTTP routes. See patterns.md. - Guard new queues: Follow
isRedisEnabled()conditional + mock token pattern in every module. NestJS DI throws on startup without mock. - Keep processor and cron: Cron schedules; processor executes. Both always required — they are complementary. See patterns.md.
- Use local Redis in dev: Never point dev machines at Upstash — idle workers exhaust free tier (500K/day) in minutes.
Anti-Patterns
- No bare
@Processor(NAME): Always pass worker options object withdrainDelayandstalledInterval. - No bare
WorkerHostextension: Always extendBaseProcessorinstead to intercept and rate-limit worker errors. - No
registerQueuewithoutdefaultJobOptions: Omitting causes unbounded Redis memory growth. - No inline numbers: Use
bull-queue.constants.ts— never write10_000,60_000,50,20,3, or5_000directly. - No unguarded
queue.add(): Wrap in try-catch; persist DB state first. - No throws in throttler increment: Catch Redis errors; return fail-open record.
- No missing mock token: Provide
getQueueTokenmock whenredisEnabled = false. - No removing processor because cron exists: They serve different roles.
- No cloud Redis in dev: Use local Docker Redis.
References
> related_skills --same-repo
> typescript-tooling
Development tools, linting, and build config for TypeScript. Use when configuring ESLint, Prettier, Jest, Vitest, tsconfig, or any TS build tooling. (triggers: tsconfig.json, .eslintrc.*, jest.config.*, package.json, eslint, prettier, jest, vitest, build, compile, lint)
> typescript-security
Secure coding practices for TypeScript. Use when validating input, handling auth tokens, sanitizing data, or managing secrets and sensitive configuration. (triggers: **/*.ts, **/*.tsx, validate, sanitize, xss, injection, auth, password, secret, token)
> typescript-language
Modern TypeScript standards for type safety and maintainability. Use when working with types, interfaces, generics, enums, unions, or tsconfig settings. (triggers: **/*.ts, **/*.tsx, tsconfig.json, type, interface, generic, enum, union, intersection, readonly, const, namespace)
> typescript-best-practices
Idiomatic TypeScript patterns for clean, maintainable code. Use when writing or refactoring TypeScript classes, functions, modules, or async logic. (triggers: **/*.ts, **/*.tsx, class, function, module, import, export, async, promise)