若是在Nodesjs开发中你的程序须要执行一些定时任务,你会怎么作?node
以前的我是这样作的:git
打开chromgithub
在github中查找关键字 nodejs 定时任务redis
选择star数最高的开源项目.....额,是它 node-schedule。api
而后按照它的api, 写相似如下的代码,基本就能把功能完成了缓存
// 肯定时间的任务,在2015年10月1日,00:00:00执行 var schedule = require("node-schedule"); var date = new Date(2015,10,1,0,0,0); var job = schedule.scheduleJob(date, function(){ console.log("执行任务"); });
完成代码后,个人心情是这样的。app
可是,老大有一天忽然说:你实现的那种方式效率过低了,网上有人用redis实现了定时器。你去看一看,下一版本改成那种实现方式。框架
经过查询网上的资料和别人的实现方式,大概整理了以下思路。ui
1.Redis 在 2.0.0 以后推出了 Pub / Sub 的指令,能够订阅和发送特定频道消息。
2.Redis 的 2.8.0 版本以后,其推出了一个新的特性——键空间消息通知(Redis Keyspace Notifications)
3.就是若是我订阅了键空间消息,那我就能够完成定时任务了。(通知订阅缓存的过时事件,获取对应的key值,使用key值来调用对应任务。 而缓存的过时时间则表示任务的具体执行时间) >.<this
首先你得保证你的Redis版本大于2.8.0。 若是不是的话,那本文到此结束。。
由于Redis默认是关闭键空间消息通知功能的,因此需求在配置中更改它,具体配置的方法和参数参考notify-keyspace-events配置
总之最好达到如下的标准就行了。
notify-keyspace-events Ex
接下来都是代码了:
本次功能是基于sails框架完成的。
首先,要在项目启动的时候开启一个Redis专门用来订阅键空间通知
var redis = require("redis"); // 建立一个用于订阅通知的client var subscriberClient = redis.createClient( ); function initRedisSubscribe() { return subscriberClient.psubscribe('__keyevent@' + 1 +'__:expired'); }
而后,你须要建立定时任务的地方,建立一条Redis缓存,过时时间为你想执行任务的时间减去当前时刻。设置任务:
var redis = require("redis"); // 建立一个用于建立任务的client var schedQueueClient = redis.createClient( ); function setProductTask(key) { return schedQueueClient.PSETEX(key, , ''); }
原理就是当缓存过时是,经过以前的订阅,咱们能获取到缓存的key值,根据key值咱们可以执行对应的任务。
大概是这样的:
// 当接收到订阅消息调用对应服务 subscriberClient.on("pmessage", function (pattern, channel, expiredKey) { var taskname = expiredKey; switch(taskname) { case 'oneTask': return ProductTaskService[taskname].apply(this,_task); break; case 'twoTask': return SitemapTaskService[taskname].apply(this,_task); break; default: break; } });
其中,我遇到比较大的俩个问题。
就是时间很差处理,由于不能像以前使用new Date(2015,10,1,0,0,0)这样来设置任务的时间了, 最好用了万能的时间库moment来解决问题
就是若是你要循环的执行任务。 作法就是你执行一次任务的时候,须要建立下一次任务的缓存。