如何在使用集群模块的Node.js应用程序中运行Cron Job?

epi*_*a30 22 cron cluster-computing node.js

我正在使用node-cron模块来调度Node.js应用程序中的任务.我还想使用核心集群模块在几个进程中运行应用程序.

在多个流程中运行应用程序最终会在每个流程中执行计划任务(例如,如果任务是发送电子邮件,则会多次发送电子邮件).

运行cron作业和集群模块的最佳实践/可能方法是什么?我应该创建一个单独的进程,只处理cron作业,不接受任何请求.如果是,我怎么能以正确的方式做到这一点?

Rah*_*mar 17

如果使用PM2,您可以使用由PM2本身提供的环境变量,该环境变量NODE_APP_INSTANCE需要PM2 2.5或更高版本.

NODE_APP_INSTANCE 环境变量可以用来确定进程之间的差异,例如你可能只想在一个进程上运行一个cronjob,你可以这样做

if(process.env.NODE_APP_INSTANCE == 0) { //schedule your cron job here since this part will be executed for only one cluster } ,

由于两个进程永远不会有相同的数字.

在PM2官方文档更多信息在这里.


epi*_*a30 11

经过一些研究后,我最终得到了" 使用Redis的分布式锁 "解决方案.有节点模块:node-redis-warlock.

希望这个答案对其他人有用.

更新.最小样本代码:

var Warlock = require('node-redis-warlock'),
    redis = require('redis');

// Establish a redis client
redis = redis.createClient();

// and pass it to warlock
var warlock = new Warlock(redis);

function executeOnce (key, callback) {
    warlock.lock(key, 20000, function(err, unlock){
        if (err) {
            // Something went wrong and we weren't able to set a lock
            return;
        }

        if (typeof unlock === 'function') {
            setTimeout(function() {
                callback(unlock);
            }, 1000);
        }
    });
}

// Executes call back only once
executeOnce('every-three-hours-lock', function(unlock) {
    // Do here any stuff that should be done only once...            
    unlock();          
});
Run Code Online (Sandbox Code Playgroud)

更新2.更详细的例子:

const CronJob = require('cron').CronJob;
const Warlock = require('node-redis-warlock');
const redis = require('redis').createClient();
const warlock = new Warlock(redis);
const async = require('async');

function executeOnce (key, callback) {
    warlock.lock(key, 20000, function(err, unlock) {
        if (err) {
            // Something went wrong and we weren't able to set a lock
            return;
        }

        if (typeof unlock === 'function') {
            setTimeout(function() {
                callback(unlock);
            }, 1000);
        }
    });
}

function everyMinuteJobTasks (unlock) {
    async.parallel([
        sendEmailNotifications,
        updateSomething,
        // etc...
    ],
    (err) => {
        if (err) {
            logger.error(err);
        }

        unlock();
    });
}

let everyMinuteJob = new CronJob({
    cronTime: '*/1 * * * *',
    onTick: function () {
        executeOnce('every-minute-lock', everyMinuteJobTasks);
    },
    start: true,
    runOnInit: true
});

/* Actual tasks */
let sendEmailNotifications = function(done) {
    // Do stuff here
    // Call done() when finished or call done(err) if error occurred
}

let updateSomething = function(done) {
    // Do stuff here
    // Call done() when finished or call done(err) if error occurred
}

// etc...
Run Code Online (Sandbox Code Playgroud)


小智 5

我认为您可以使用节点集群模块,并且您可以编写代码以仅在主集群中运行

const cluster = require('cluster');

if (cluster.isMaster) {
     // Write your code which you want to execute in the master cluster only
}
Run Code Online (Sandbox Code Playgroud)

这是处理集群的节点方式,当然,您可以使用任何工具(例如 pm2)来处理此问题。