nuxt-simple-bullmq
Nuxt Simple BullMQ Module
Simple Nuxt 3 module using BullMQ and Redis for doing amazing things.
Features
- ⛰ Foo
- 🚠 Bar
- 🌲 Baz
Quick Setup
Install the module in your Nuxt application with one command:
npx nuxi module add nuxt-simple-bullmq
NOTE: This is only tested with NodeJS 21 (not cloudflare/vercel etc) and Nuxt 4 with experimental features (see test workflows/files for more)
Add the config
// nuxt.config.ts
{
runtimeConfig: {
redis: {
url: 'redis://localhost:6379'
}
},
bullMq: {
// Where to load defined workers from (defineWorker files)
// this is optional, and will default to [ '<serverDir>/workers' ]
workerDirs: [ '/workers' ], // base path will be your "serverDir" e.g ./server/some-path
}
}
or use NUXT_REDIS_URL in your $environment
That's it! You can now use BullMQ in your Nuxt app ✨
Usage
Workers
A worker lives in its own file and each worker is registered as a separate nitro plugin.
// ./server/workers/default,ts
export default defineWorker('default', {
async sendWelcomeEmail({job, logger, lockId}) {
logger.info(`Sending welcome email to ${job.data.email}`)
},
// magic catch-all event handler (for uncaught events):
catchAll({job, logger}) {
logger.debug(`Uncaught event: ${job.name}!`, job.data)
}
}, {
//optional: default //comment
concurrency: 1, //how many of each worker to run
});
Jobs
Jobs are handled through callbacks, they can be in their own files, defined directly on the worker etc.
Note: There is no typing for dispatching jobs - yet :/ One solution can be to use a constant mapping e.g
const JobNames = {someKey: 'someValue'}
// ./server/jobs/sendWelcomeEmail.ts
export default defineJobHandler(({job, logger}) => {
logger.debug(job.name, job.data)
})
Validated job handlers
// ./server/jobs/sendWelcomeEmail.ts
import {z} from 'zod';
export default defineValidatedJobHandler(
z.object({userId: z.string()}),
async ({data, job, logger}) => {
// data contains the validated payload from the schema
// data is also typed: {userId:string}
},
);
Note: Validates input before processing the job
Delaying jobs
// ./server/jobs/onboarding/sendTipsAndTricks.ts
import {z} from 'zod'
import {DelayedError} from 'bullmq';
export default defineValidatedJobHandler(
z.object({userId: z.string().uuid()}),
async ({data: {userId}, job, logger, lockId}) => {
const DELAY_MS = 1_800_000 // 30 minutes
// do some checks...
if (!await userHasVerifierEmail() && !hasBeenMoreThan24HoursSinceSignUp()) {
logger.info('Preconditions not met, delaying job...')
await job.moveToDelayed(Date.now() + DELAY_MS, lockId)
throw new DelayedError();
}
logger.info(`Sending Tips & Tricks to user ${userId}`)
},
)
Dispatching Jobs
// ./server/route/dispatch.ts
import {dispatchJob} from '#imports'
export default defineEventHandler(async event => {
await dispatchJob(
'sendWelcomeEmail',
{userId: 'abc'},
// Optional:
{queueName: 'default', attempts: 1, backoff: {strategy: 'exponential', } },
)
})
Validated job dispatch
// ./server/route/typed-dispatch.ts
import {dispatchValidatedJob} from '#imports'
export default defineEventHandler(async event => {
await dispatchValidatedJob(
'sendWelcomeEmail',
z.object({userId: z.string()}),
{userId: 'abc'},
{queueName: 'default'},
)
})
This will validate the input before emitting the job to redis
Additional options
You can pass the same options that are passed as the third argument when calling
emittodispatchJobanddispatchValidatedJobas well.
// ./server/route/name.ts
import {useQueue} from '#imports'
//e.g using H3 event handlers
export default defineEventHandler(async event => {
const queue = useQueue('default');
await queue.emit('sendWelcomeEmail', {userId: 'some-string'}, {
//Optionals (with their defaults)
queueName: 'default',
//optionals without defaults
deduplicationId: 'some-string', // can be anything, defaults to the event name.
ttl: 500, // when the deduplication should expire
delay: 500, // a delay to when this will run (good for notifications)
})
//validate schema first:
await queue.emit('sendWelcomeEmail', {userId: 'some-string'}, {
schema: z.object({userId: z.string()}), // optional
//... other options
})
})
Roadmap
- Add handlers
- Worker per plugin
- Validation dispatch/handler
- File based listeners (Laravel style with a "dispatch" method)
- Flow producers
- Different lib/platform (e.g Vercel/Cloudflare)
Contribution
Local development
# Install dependencies
npm install
# Generate type stubs
npm run dev:prepare
# run redis via docker (add -s to detach and continue using the terminal for other stuff)
docker compose -f ./playground/compose.yml up [-d]
# to stop docker stuff:
docker compose -f ./playground/compose.yml down
# Develop with the playground
npm run dev
# Build the playground
npm run dev:build
# Run ESLint
npm run lint
# Run Vitest
npm run test
npm run test:watch
# Release new version
npm run release
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.8.4 | ^3.0 | MIT | |
| 1.8.3 | ^3.0 | MIT | |
| 1.8.2 | ^3.0 | MIT | |
| 1.8.1 | ^3.0 | MIT | |
| 1.8.0 | ^3.0 | MIT | |
| 1.7.4 | ^3.0 | MIT | |
| 1.7.3 | ^3.0 | MIT | |
| 1.7.2 | ^3.0 | MIT | |
| 1.7.1 | ^3.0 | MIT | |
| 1.7.0 | ^3.0 | MIT | |
| 1.6.1 | ^3.0 | MIT | |
| 1.6.0 | ^3.0 | MIT | |
| 1.5.6 | ^3.0 | MIT | |
| 1.5.5 | ^3.0 | MIT | |
| 1.5.4 | ^3.0 | MIT | |
| 1.5.3 | ^3.0 | MIT | |
| 1.5.2 | ^3.0 | MIT | |
| 1.5.1 | ^3.0 | MIT | |
| 1.5.0 | ^3.0 | MIT | |
| 1.4.0 | ^3.0 | MIT | |
| 1.3.5 | ^3.0 | MIT | |
| 1.3.4 | ^3.0 | MIT | |
| 1.3.3 | ^3.0 | MIT | |
| 1.3.2 | ^3.0 | MIT | |
| 1.3.0 | ^3.0 | MIT | |
| 1.2.8 | ^3.0 | MIT | |
| 1.2.7 | ^3.0 | MIT | |
| 1.2.6 | ^3.0 | MIT | |
| 1.2.5 | ^3.0 | MIT | |
| 1.2.4 | ^3.0 | MIT |
Showing the latest 30 of 53. See every release on npm