Использование cron с redlock и кластером в nodejs

Я хочу запускать задачу каждую минуту и ​​для этого я выбрал cron. Теперь я запускаю узел, используя модуль кластера, и он порождает 4 процесса, но я хочу запускать cron только один раз для каждого процесса в минуту.

Теперь одно из решений этой проблемы — запустить его в мастере. Но это не поможет, если я запущу более одного экземпляра с кластером на каждом экземпляре.

Вот и решил поискать запорные механизмы. Я нашел redlock, и это пример кода:

const redlock = new Redlock([redisClient], {
    driftFactor: 0.01, // time in ms
    retryCount: 2,
    retryDelay: 200 // time in ms
});

redlock.on('clientError', function (err) {
    console.error('REDLOCK REDIS ERROR: ', err);
});

const LOCK_KEY = "GOHAN_REMINDER_LOCK";
const LOCK_KEY_TTL = 10000;


const job = new CronJob({
    cronTime: '* * * * *',
    onTick: function () {
        /*
         * Runs every minute
         */
        redlock.lock(LOCK_KEY, LOCK_KEY_TTL).then(function (lock) {

            return Bluebird.try(function () {
                const currentMilitaryTime = moment.utc().format("HH:mm");

                return ChildReminder.getRemindersByDate(currentMilitaryTime).then(function (reminders) {
                    console.log("REMINDERS FOR TIME " + currentMilitaryTime + " :", reminders);
                });
            }).then(function () {
                return lock.unlock()
                    .catch(function (err) {
                        console.error("REDLOCK UNLOCK ERROR: ", err);
                    });
            });
        });

    },
    start: false,
    timeZone: 'UTC'
});

job.start();

Журналы, которые я получаю:

REMINDERS FOR TIME 06:08 : [ anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 4,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399630',
    created_at: 2016-11-29T06:07:12.296Z,
    updated_at: 2016-11-29T06:07:12.296Z,
    time: '06:08',
    repeat: '1111111',
    on: true },
  anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 5,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399638',
    created_at: 2016-11-29T06:07:19.385Z,
    updated_at: 2016-11-29T06:07:19.385Z,
    time: '06:08',
    repeat: '1111111',
    on: true } ]
REMINDERS FOR TIME 06:08 : [ anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 4,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399630',
    created_at: 2016-11-29T06:07:12.296Z,
    updated_at: 2016-11-29T06:07:12.296Z,
    time: '06:08',
    repeat: '1111111',
    on: true },
  anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 5,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399638',
    created_at: 2016-11-29T06:07:19.385Z,
    updated_at: 2016-11-29T06:07:19.385Z,
    time: '06:08',
    repeat: '1111111',
    on: true } ]
REMINDERS FOR TIME 06:08 : [ anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 4,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399630',
    created_at: 2016-11-29T06:07:12.296Z,
    updated_at: 2016-11-29T06:07:12.296Z,
    time: '06:08',
    repeat: '1111111',
    on: true },
  anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 5,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399638',
    created_at: 2016-11-29T06:07:19.385Z,
    updated_at: 2016-11-29T06:07:19.385Z,
    time: '06:08',
    repeat: '1111111',
    on: true } ]
REMINDERS FOR TIME 06:08 : [ anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 4,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399630',
    created_at: 2016-11-29T06:07:12.296Z,
    updated_at: 2016-11-29T06:07:12.296Z,
    time: '06:08',
    repeat: '1111111',
    on: true },
  anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 5,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399638',
    created_at: 2016-11-29T06:07:19.385Z,
    updated_at: 2016-11-29T06:07:19.385Z,
    time: '06:08',
    repeat: '1111111',
    on: true } ]
REMINDERS FOR TIME 06:08 : [ anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 4,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399630',
    created_at: 2016-11-29T06:07:12.296Z,
    updated_at: 2016-11-29T06:07:12.296Z,
    time: '06:08',
    repeat: '1111111',
    on: true },
  anonymous {
    user_id: '764418c2-a874-495c-b8c1-cc555ce9b202',
    child_id: '8c8a273f-3a84-4a66-9fa7-bb9e6c5fcf0a',
    reminder_id: 5,
    label: 'textvoice1',
    mode: 'textvoice',
    text_message: 'How you doin\'',
    voice_message: '1480399638',
    created_at: 2016-11-29T06:07:19.385Z,
    updated_at: 2016-11-29T06:07:19.385Z,
    time: '06:08',
    repeat: '1111111',
    on: true } ]

В основном задание выполняется 4-5 раз, чего я не хочу. Любая помощь будет оценена по достоинству. Спасибо.

РЕДАКТИРОВАТЬ № 1: я попытался изменить retryCount на 0 и увеличить/уменьшить TTL, но не получил желаемых результатов.

Ссылки на пакеты:

  1. Redlock
  2. Cron

person Abhyudit Jain    schedule 29.11.2016    source источник


Ответы (1)


Кажется, что если экземпляр получает блокировку и освобождает ее до того, как второй попытается ее получить, оба экземпляра будут работать. Вам понадобится что-то более надежное.

Я только что написал небольшой модуль для узла cronivo, он использует LaterJs и Redis, и это должно работать для вас, по крайней мере, это может дать вам некоторые идеи.

person Ivo Udelsmann    schedule 07.12.2016
comment
Я нашел альтернативный способ. Я не снимаю блокировку вручную, а просто полагаюсь на TTL для блокировки. Таким образом, я не сталкивался с какими-либо проблемами до сих пор. Можете ли вы сказать мне, возможны ли какие-либо проблемы таким образом? - person Abhyudit Jain; 09.12.2016
comment
Если экземпляр занят и завершает попытку выполнения после TTL, он будет выполняться, даже если не должен. Если ваш TTL достаточно велик, это очень маловероятно. Я не думаю, что этот подход очень хорош, но он может сработать. - person Ivo Udelsmann; 09.12.2016
comment
Я не возражаю против запуска еще одного процесса, но я не хочу, чтобы работа выполнялась дважды или трижды... мой ttl составляет 60 секунд... Я хочу каждую минуту проверять, какие напоминания нужно отправить. Итак, если в 06:11 процесс получает напоминания на 06:11, то в 06:12 мне нужны напоминания на 06:12. Чего я не хочу, так это 4 процесса получения напоминаний на 06:11, потому что тогда они будут отправлены 4 раза. - person Abhyudit Jain; 10.12.2016