> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/taskforcesh/bullmq/llms.txt
> Use this file to discover all available pages before exploring further.

# Repeat Strategies

> Learn about different strategies for scheduling repeatable jobs in BullMQ

BullMQ comes with two predefined strategies for creating repeatable jobs:

* **Every strategy**: Schedule jobs at fixed intervals measured in milliseconds
* **Cron strategy**: Use cron expressions for intricate scheduling patterns

Additionally, BullMQ lets you create **custom strategies**, giving you the flexibility to define your own logic for setting job intervals.

## Every Strategy

The every strategy is used when you want to produce repeatable jobs at specific intervals:

```typescript theme={null}
import { Queue, Worker } from 'bullmq';

const connection = {
  host: 'localhost',
  port: 6379,
};

const myQueue = new Queue('my-repeatable-jobs', { connection });

// Upserting a repeatable job in the queue
await myQueue.upsertJobScheduler(
  'repeat-every-10s',
  {
    every: 10000, // Job will repeat every 10000 milliseconds (10 seconds)
  },
  {
    name: 'every-job',
    data: { jobData: 'data' },
    opts: {}, // Optional additional job options
  },
);

// Worker to process the jobs
const worker = new Worker(
  'my-repeatable-jobs',
  async (job) => {
    console.log(`Processing job ${job.id} with data: ${job.data.jobData}`);
  },
  { connection },
);
```

### Common Intervals

```typescript theme={null}
// Every second
{ every: 1000 }

// Every 30 seconds
{ every: 30000 }

// Every minute
{ every: 60000 }

// Every 5 minutes
{ every: 5 * 60 * 1000 }

// Every hour
{ every: 60 * 60 * 1000 }

// Every day
{ every: 24 * 60 * 60 * 1000 }
```

<ParamField path="every" type="number" required>
  Interval in milliseconds between job executions
</ParamField>

<Note>
  You cannot use both `pattern` and `every` options together. Choose one strategy per scheduler.
</Note>

## Cron Strategy

The cron strategy leverages the [cron-parser](https://www.npmjs.com/package/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.

### Cron Expression Format

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.

### Basic Example

```typescript theme={null}
import { Queue, Worker } from 'bullmq';

const connection = {
  host: 'localhost',
  port: 6379,
};

const myQueue = new Queue('my-cron-jobs', { connection });

// Upserting a job with a cron expression
await myQueue.upsertJobScheduler(
  'weekday-morning-job',
  {
    pattern: '0 0 9 * * 1-5', // Runs at 9:00 AM every Monday to Friday
  },
  {
    name: 'cron-job',
    data: { jobData: 'morning data' },
    opts: {}, // Optional additional job options
  },
);

// Worker to process the jobs
const worker = new Worker(
  'my-cron-jobs',
  async (job) => {
    console.log(
      `Processing job ${job.id} at ${new Date()} with data: ${
        job.data.jobData
      }`,
    );
  },
  { connection },
);
```

### Common Cron Patterns

```typescript theme={null}
// 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 * *'
```

<ParamField path="pattern" type="string" required>
  Cron expression for scheduling (e.g., '0 \* \* \* \*' for every hour)
</ParamField>

### Timezone Support

Cron expressions support timezone differences and daylight saving time transitions, crucial for tasks that depend on local times:

```typescript theme={null}
await myQueue.upsertJobScheduler(
  'tokyo-morning-job',
  {
    pattern: '0 0 9 * * *', // 9 AM
    tz: 'Asia/Tokyo',
  },
  {
    name: 'morning-task',
    data: {},
  },
);
```

### Special Characters

Cron patterns support special characters for flexible scheduling:

* **`*`** - Any value
* **`,`** - Value list separator (e.g., `1,3,5`)
* **`-`** - Range of values (e.g., `1-5`)
* **`/`** - Step values (e.g., `*/5` for every 5 units)
* **`L`** - Last day of the month (day field only)

<Info>
  If you're new to cron expressions, [Wikipedia](https://en.wikipedia.org/wiki/Cron) is an excellent starting point to learn how to use them.
</Info>

## Custom Strategy

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.

<Warning>
  Only **one** repeatStrategy can be defined for a given queue. The strategy applies to all job schedulers in that queue.
</Warning>

### Implementation Requirements

A custom repeat strategy is a function with this signature:

```typescript theme={null}
type RepeatStrategy = (
  millis: number,
  opts: RepeatOptions,
  jobName: string,
) => number | undefined;
```

* **millis**: Current timestamp in milliseconds
* **opts**: Repeat options containing pattern and other settings
* **jobName**: Name of the job (for conditional logic)
* **Returns**: Next execution timestamp in milliseconds, or undefined to stop

### RRULE Example

Here's an example using [RRULE](https://jkbrzt.github.io/rrule/) for complex recurrence patterns:

```typescript theme={null}
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 seconds
await myQueue.upsertJobScheduler(
  'colibris',
  {
    pattern: 'RRULE:FREQ=SECONDLY;INTERVAL=10;WKST=MO',
  },
  {
    data: { color: 'green' },
  },
);

// Repeat job every 20 seconds
await 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 },
);
```

<Warning>
  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.
</Warning>

### Custom Strategy Best Practices

<Steps>
  <Step title="Handle edge cases">
    Return `undefined` when no more jobs should be scheduled:

    ```typescript theme={null}
    if (nextTime > endDate) return undefined;
    ```
  </Step>

  <Step title="Respect startDate">
    Always check if startDate is in the future:

    ```typescript theme={null}
    const currentDate = opts.startDate && new Date(opts.startDate) > new Date(millis)
      ? new Date(opts.startDate)
      : new Date(millis);
    ```
  </Step>

  <Step title="Use job name for conditional logic">
    Different jobs can have different scheduling behavior:

    ```typescript theme={null}
    if (jobName === 'priority-task') {
      // Special scheduling logic
    }
    ```
  </Step>

  <Step title="Configure in both Queue and Worker">
    Ensure consistent behavior across your application:

    ```typescript theme={null}
    const settings = { repeatStrategy: myStrategy };
    const queue = new Queue('name', { settings });
    const worker = new Worker('name', processor, { settings });
    ```
  </Step>
</Steps>

## Default Repeat Strategy

BullMQ's default repeat strategy for cron patterns:

```typescript theme={null}
const defaultRepeatStrategy = (
  millis: number,
  opts: RepeatOptions,
): number | undefined => {
  const { pattern } = opts;

  const dateFromMillis = new Date(millis);
  const startDate = opts.startDate && new Date(opts.startDate);
  const currentDate = startDate > dateFromMillis ? startDate : dateFromMillis;
  
  const interval = parseExpression(pattern, {
    ...opts,
    currentDate,
  });

  try {
    if (opts.immediately) {
      return new Date().getTime();
    } else {
      return interval.next().getTime();
    }
  } catch (e) {
    // Ignore error
  }
};
```

## Comparison

| Feature              | Every Strategy     | Cron Strategy              | Custom Strategy            |
| -------------------- | ------------------ | -------------------------- | -------------------------- |
| **Precision**        | Milliseconds       | Seconds                    | Custom                     |
| **Complexity**       | Simple             | Moderate                   | Flexible                   |
| **Use Case**         | Fixed intervals    | Time-based schedules       | Complex patterns           |
| **Timezone Support** | No                 | Yes                        | Custom                     |
| **DST Handling**     | No                 | Yes                        | Custom                     |
| **Example**          | `{ every: 60000 }` | `{ pattern: '0 * * * *' }` | `{ pattern: 'RRULE:...' }` |

## Related Topics

<CardGroup cols={2}>
  <Card title="Repeat Options" icon="sliders" href="/schedulers/repeat-options">
    Configure start dates, end dates, limits, and more
  </Card>

  <Card title="Overview" icon="book" href="/schedulers/overview">
    Learn the basics of Job Schedulers
  </Card>

  <Card title="Management" icon="list-check" href="/schedulers/management">
    Manage and monitor job schedulers
  </Card>
</CardGroup>

## API Reference

* [Queue.upsertJobScheduler API Reference](https://api.docs.bullmq.io/classes/v5.Queue.html#upsertjobscheduler)
* [cron-parser Documentation](https://www.npmjs.com/package/cron-parser)
* [RRULE Documentation](https://jkbrzt.github.io/rrule/)
