作者: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 Robanlee@gmail.com
 */ //加载函数,集中加载一些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控制台会输出(这个任务在没有取消的情况下,每分钟都会执行):

第二分钟:

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开发一个消息队列以及定时任务处理的更多相关文章

  1. 如何使用NODEJS+REDIS开发一个消息队列

    作者: RobanLee 原创文章,转载请注明: 萝卜李 http://www.robanlee.com MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应 ...

  2. 什么鬼,面试官竟然让我用Redis实现一个消息队列!!?

    GitHub 9.4k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 9.4k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 9.4k Star 的 ...

  3. Redis 学习笔记(六)Redis 如何实现消息队列

    一.消息队列 消息队列(Messeage Queue,MQ)是在分布式系统架构中常用的一种中间件技术,从字面表述看,是一个存储消息的队列,所以它一般用于给 MQ 中间的两个组件提供通信服务. 1.1 ...

  4. Redis+php-resque实现消息队列

      服务器硬件配置 Dell PowerEdge R310英特尔单路机架式服务器 Intel Xeon Processor X3430 2.4GHz, 8MB Cache 8GB内存(2 x 4GB) ...

  5. Redis实现简单消息队列

    http://www.jianshu.com/p/9c04890615ba 任务异步化 打开浏览器,输入地址,按下回车,打开了页面.于是一个HTTP请求(request)就由客户端发送到服务器,服务器 ...

  6. Delayer 基于 Redis 的延迟消息队列中间件

    Delayer 基于 Redis 的延迟消息队列中间件,采用 Golang 开发,支持 PHP.Golang 等多种语言客户端. 参考 有赞延迟队列设计 中的部分设计,优化后实现. 项目链接:http ...

  7. Spring Cloud(7):事件驱动(Stream)分布式缓存(Redis)及消息队列(Kafka)

    分布式缓存(Redis)及消息队列(Kafka) 设想一种情况,服务A频繁的调用服务B的数据,但是服务B的数据更新的并不频繁. 实际上,这种情况并不少见,大多数情况,用户的操作更多的是查询.如果我们缓 ...

  8. 进阶高阶IoT架构-教你如何简单实现一个消息队列

    前言 消息队列是软件系统领域用来实现系统间通信最广泛的中间件.基于消息队列的方式是指由应用中的某个系统负责发送消息,由关心这条消息的相关系统负责接收消息,并在收到消息后进行各自系统内的业务处理.消息可 ...

  9. skynet源代码学习 - 从全局队列中弹出/压入一个消息队列过程

    学习云风的skynet源代码,简单记录下. void skynet_globalmq_push(struct message_queue * queue) { struct global_queue ...

随机推荐

  1. uva 508 Morse Mismatches

    Samuel F. B. Morse is best known for the coding scheme that carries his name. Morse code is still us ...

  2. php函数、类和对象以及类的封装、继承、类的静态方法、静态属性

    1.函数     php内置函数可以直接使用,如果没有安装php扩展即可     自定义函数 //函数function 函数名 function dump($var = null){ //支出默认参数 ...

  3. 'data-'属性的作用是什么?

    data-为前端开发者提供自定义的属性,这些属性集可以通过对象的dataset属性获取,不支持该属性的浏览器可以通过 getAttribute方法获取.ppk提到过使用rel属性,lightbox库推 ...

  4. PHP根据经纬度,计算2点之间的距离的2种方法

    计算地球表面2点之间的球面距离 /** * @param $lat1 * @param $lng1 * @param $lat2 * @param $lng2 * @return int */ fun ...

  5. yii2安装与初始化-Yii2学习笔记(一)

    一.安装项目: 使用composer下载安装yii2 advanced安装包: composer create-project yiisoft/yii2-app-advanced advanced(自 ...

  6. 【转】Android虚拟平台的编译和整合

    原文网址:http://blog.csdn.net/rickleaf/article/details/6369065 概要 Android从2008年开始到本文写的2011年,短短三年的时间里成为手机 ...

  7. 几个js的linq实现

    几个js的linq实现 linqjs.codeplex.com jslinq.codeplex.com javascriptiqueryable.codeplex.com fromjs.codeple ...

  8. UESTC_The Most Wonderful Competition CDOJ 56

    The Most Wonderful Competition Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB ...

  9. First Missing Positive 解答

    Question Given an unsorted integer array, find the first missing positive integer. For example,Given ...

  10. Remove Nth Node From End of List 解答

    Question Given a linked list, remove the nth node from the end of list and return its head. For exam ...