The cron strategy leverages the cron-parser library to use cron expressions for scheduling jobs with greater specificity. This approach is ideal for jobs requiring execution at precise times or intervals, such as automated reports or maintenance tasks.
BullMQ supports a 6-field cron format with an optional seconds field:
* * * * * *┬ ┬ ┬ ┬ ┬ ┬│ │ │ │ │ ││ │ │ │ │ └ day of week (0 - 7, 1L - 7L, where 0 or 7 is Sunday)│ │ │ │ └───── month (1 - 12)│ │ │ └────────── day of month (1 - 31, L for the last day of the month)│ │ └─────────────── hour (0 - 23)│ └──────────────────── minute (0 - 59)└───────────────────────── second (0 - 59, optional)
This format includes the optional second field, which is not typically available in standard cron schedules, allowing for even more precise scheduling.
// Every minute'* * * * *'// Every 5 minutes'*/5 * * * *'// Every hour at minute 30'30 * * * *'// Every day at midnight'0 0 * * *'// Every day at 2:30 PM'30 14 * * *'// Every Monday at 9 AM'0 9 * * 1'// Every 1st of the month at midnight'0 0 1 * *'// Every weekday at 6 PM'0 18 * * 1-5'// Every 15 minutes during business hours (9 AM - 5 PM, Mon-Fri)'*/15 9-17 * * 1-5'// Every 3 hours'0 */3 * * *'// Last day of the month at midnight'0 0 L * *'
It’s possible to define a different strategy to schedule repeatable jobs. The idea is that the repeat strategy, based on a pattern and the latest job’s milliseconds, returns the next desired timestamp.
Only one repeatStrategy can be defined for a given queue. The strategy applies to all job schedulers in that queue.
Here’s an example using RRULE for complex recurrence patterns:
import { Queue, Worker } from 'bullmq';import { rrulestr } from 'rrule';import type { RepeatOptions } from 'bullmq';const settings = { repeatStrategy: (millis: number, opts: RepeatOptions, _jobName: string) => { const currentDate = opts.startDate && new Date(opts.startDate) > new Date(millis) ? new Date(opts.startDate) : new Date(millis); const rrule = rrulestr(opts.pattern); if (rrule.origOptions.count && !rrule.origOptions.dtstart) { throw new Error('DTSTART must be defined to use COUNT with rrule'); } const next_occurrence = rrule.after(currentDate, false); return next_occurrence?.getTime(); },};const myQueue = new Queue('Paint', { settings });// Repeat job every 10 secondsawait myQueue.upsertJobScheduler( 'colibris', { pattern: 'RRULE:FREQ=SECONDLY;INTERVAL=10;WKST=MO', }, { data: { color: 'green' }, },);// Repeat job every 20 secondsawait myQueue.upsertJobScheduler( 'pigeons', { pattern: 'RRULE:FREQ=SECONDLY;INTERVAL=20;WKST=MO', }, { data: { color: 'gray' }, },);const worker = new Worker( 'Paint', async (job) => { console.log('Processing', job.data.color); }, { settings },);
The repeat strategy setting must be provided in both the Queue and Worker classes. The Queue uses it when first adding the job to calculate the next iteration. After that, the Worker uses its configured settings.