若是在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來解決問題
就是若是你要循環的執行任務。 作法就是你執行一次任務的時候,須要建立下一次任務的緩存。