使用NODEJS+REDIS开发一个消息队列以及定时任务处理

作者:RobanLee

原创文章,转载请注明: 萝卜李 http://www.robanlee.com

源码在这里: https://github.com/robanlee123/RobCron




时间有限,就不详细注释,有问题或者意见欢迎@我,也欢迎大家批评指正.

本文所必须的一些资料如下:

1. NODEJS ==> 可以去NODEJS.ORG下载最新的源码.
2. Redis ==> Redis.io
3. KUE ==> Nodejs的一个开源队列系统
4. NODE-SCHEDULE ==> NODEJS 一个开源调度系统

废话不多说,先来介绍任务的流程:

1. NODEJS或者PHP或者其他语言 写入REDIS 一个计划任务, 比如每分钟做某件事,这里就用SAYHELLO来代替好了
2. 使用NODEJS读取这个任务,并将它转换为NODE的调度任务(node-schedule 来完成)
3. 调度器[node-schedule]根据设定的规则来分发任务.
4. KUE接受任务,并且加入列队,执行.
5. DONE

 

STEP1: 创建一个任务

/**

 * Add task

 * @author [email protected]

 */



//加载函数,集中加载一些LIB,这个源码请参照最后的附属文件

var loader = require('./loader');  



function addTask(opts){

        new loader(this); 

        

        //默认设置

        this.opts = {

                keyIDs:'schedule:job:ids',

                keyLists:'schedule:job:list',

                keyJob:'schedule:job:'

        }

        

        //合并配置,类似JQUERY: extend

        this.mergeParams(opts);  

};



//Merge options

addTask.prototype.mergeParams = function ( param ){

        if(undefined === this.opts ) {

                return false;

        }

        

        for(var x in param) { 

                if(param[x] != undefined && '' != param[x]) {

                        this.opts[x] = param[x];

                }

        }

};



//添加数据方法

addTask.prototype.pushData = function ( data ){ 

        if(undefined == data ) {

                console.log('--ERROR:data is null');

                return false;

        }

        this.getIncr.call(this,function(response,obj){

                var id = response;

                obj.redisClient.rpush(obj.opts.keyLists,id,function(err,response){

                        if(err) throw err;

                });

         

                data.id = id;

                var m = obj.redisClient.multi();

                for(var x in data) {

                        m.hset( obj.opts.keyJob+id,x,data[x] );

                }

                

                m.exec(function(err,response){

                        if(err) throw err; 

                        console.log('[info] Task: ['+data.name+'] has been set successful!');

                });   

               

        }); 

};



//获取REDIS目前的自增ID

addTask.prototype.getIncr = function (callBack){

        var obj = this; 

        this.redisClient.incr(this.opts.keyIDs,function(err,response){

                console.log("[info] Current id is : " + response);

                callBack(response, obj);

        });

};

 

 

加载这个lib 写入一个DEMO:

var data = { 

        'name':'taskDemo',

        'created':Date.now(),

        'state':1,

        'type':'untitled',

        'rule':'*/1 * * * *'  //这个任务规则可以为CRONTAB的规则,这个表示每分钟执行一次

};



var job = new addTask();

job.pushData(data);

 

执行这个脚本,如果一切正常,你会看到如下信息:

NODEJS 输出:

REDIS:

 

 

接下来就是获取数据,并且转换为调度任务了,

源码:

var loader = require('./loader');

var taskLog = require("./TaskLog");



function scheduleTask(){

        new loader(this); 

        this.opts = {

                keyIDs:'schedule:job:ids',

                keyLists:'schedule:job:list',

                keyJob:'schedule:job:'

        }

        

        this.task = {

                taskDemo:undefined

        };

        

        //监听取消任务操作

        this.listenCancel();

};



scheduleTask.prototype.setScheduleTask = function (data,obj){ 

        this.task[data.name] =  this.libs['node-schedule'].scheduleJob(data.rule,function(){

                obj.setQueue(data);

                console.log('[info] Task :' + data.name + ' has been set in queue!');

        });

         

};



scheduleTask.prototype.setQueue = function (datas){

        

        var jobs = this.libs.kue.createQueue(); 

        jobs.create(datas.name,{

                'name:':datas.name,

                'state':1

        }).save();

         

        console.log("[info] Task ["+datas.name+"] has been queued!");

        

        this.setLog(datas);

};



scheduleTask.prototype.setLog = function (responseData){

        var logData = {

                jobid:responseData.id,

                name:responseData.name,

                result:1

        };

                                        

        new taskLog(logData);

        console.log("[info] Task has been loged");

};





scheduleTask.prototype.getJob = function (){

        this.getJobIndex.call(this,function(response,obj){

                for(var x in response ) {

                        obj.redisClient.hgetall(obj.opts.keyJob+response[x],function(err,data){

                                console.log("[info] Task:["+data.name+"] has been loaded!");

                                obj.setScheduleTask(data, obj);

                        });

                }

        });

};





scheduleTask.prototype.getJobIndex = function(callBack){

        //Read tasks from <list schedule:job:list>

        var o = this;

        this.redisClient.lrange(this.opts.keyLists,0,-1,function(err,response){

                if(err) throw err;

                callBack(response, o);

        });

};



scheduleTask.prototype.listenCancel = function (){

        var job = this.libs.kue.createQueue();

        var that = this;



        job.process('cancelJob',function(data,done){  

                that.task[data.data.data].cancel();

                console.log('[info] Task: '+data.data.data + ' has been canceled') ;

                done();

        });

}

 

执行代码:

var x = new scheduleTask();

x.getJob();

 

等待一分钟后,NODEJS控制台会输出(这个任务在没有取消的情况下,每分钟都会执行):

 

第二分钟:

使用NODEJS+REDIS开发一个消息队列以及定时任务处理

 

REDIS 现在的数据:

使用NODEJS+REDIS开发一个消息队列以及定时任务处理

这个数据中增加了KUE的一些任务, q:job:[]:inactive 这个就标识任务还未被执行,执行后的任务状态有

complete active failed delay 四种

 

至此,就只剩下执行任务的步骤了

var loader = require('./loader');



function execTask(){

        new loader(this); 

        

        var job = this.libs.kue.createQueue();

        job.process('taskDemo',function(data,done){

                console.log('[info] Task:'+data.type+'#'+data.id+' has been executed successful!');

                

                

                //DONE之前可以做你想要做的事情

                

                done(); //千万别忘记调用此方法

        });

        

        

}



//添加一个取消定时任务的KUE任务

execTask.prototype.addCancelJob = function (){

        var job =this.libs.kue.createQueue();

        job.create('cancelJob', {data:'taskDemo'}).save();

        console.log('[info] Task: cancelJob has been send!');

}

 

执行这个脚本:

var et = new execTask();



//取消定时任务

et.addCancelJob();

 

 

执行后会有2个结果

1. 程序会执行当前列队里的任务.

2. 定时任务会被取消,下一分钟后任务不会再由SCHEDULE分配

 

任务执行结果:

 

取消任务的回应:

使用NODEJS+REDIS开发一个消息队列以及定时任务处理

注意最后一行…

你可能感兴趣的:(nodejs)