bullmq icon indicating copy to clipboard operation
bullmq copied to clipboard

Repeat options startDate and every are incompatible

Open richardgarnier opened this issue 2 years ago • 3 comments

When both startDate and every are set on a job, startDate is ignored. I think the code responsible for this is here.

My use case was to use the startDate in order to spread repeatable jobs during the day. I want them to run once every day, but not at the same time. If you are open to a PR, I can change the getNextMillis implementation to repeat at a given interval based on the startDate.

Otherwise it would be probably nice to:

  • mention in the docs that startDate will be ignored if every is set
  • throw an exception during job construction, to notify that this use case will not work

richardgarnier avatar Oct 17 '22 04:10 richardgarnier

In case someone else have the issue, in the meantime you can fix the problem by providing a repeat strategy.

import { getNextMillis, RepeatOptions } from 'bullmq';

export function syncRepeatStrategy(
  millis: number,
  opts: RepeatOptions,
): number {
  if (!opts.startDate || !opts.every) {
    return getNextMillis(millis, opts);
  }

  const startMillis = new Date(opts.startDate).getTime();
  if (millis < startMillis) {
    return startMillis;
  }

  return (
    startMillis + Math.ceil((millis - startMillis) / opts.every) * opts.every
  );
}

And pass it to the Queue constructor:

new Queue('queue', { settings: { repeatStrategy: syncRepeatStrategy } });

richardgarnier avatar Oct 18 '22 04:10 richardgarnier

@richardgarnier thank you for making this issue and providing the workaround! I found it very helpful.

Just a quick note, the getNextMillis function returns number | undefined which isn't compatible with your syncRepeatStrategy.

It's also possible to import the RepeatStrategy type from bullmq: https://github.com/taskforcesh/bullmq/blob/4c548735d3c2489f2bdc1cfa870703db6f11f752/src/types/repeat-strategy.ts#L3-L7 which allows us to rewrite syncRepeatStrategy as:

import { getNextMillis, RepeatStrategy } from 'bullmq';

export const syncRepeatStrategy: RepeatStrategy = (millis, opts) => {
  if (!opts.startDate || !opts.every) {
    return getNextMillis(millis, opts);
  }

  const startMillis = new Date(opts.startDate).getTime();
  if (millis < startMillis) {
    return startMillis;
  }

  return (
    startMillis + Math.ceil((millis - startMillis) / opts.every) * opts.every
  );
};

nktnet1 avatar Feb 14 '24 06:02 nktnet1

An alternative solution is to use the pattern and startDate in the RepeatOptions, my use case was to trigger a job once a day in specific time, so i need to trigger that every 24hr after startDate or pass the pattern option:

image

This will be triggered every day at 06:36 PM

mbirali avatar Apr 23 '24 19:04 mbirali