美文网首页笔戈 Web Team
Nodejs中使用Redis来完成定时任务

Nodejs中使用Redis来完成定时任务

作者: 天青色等烟雨 | 来源:发表于2015-09-15 16:10 被阅读2803次

    如果在Nodesjs开发中你的程序需要执行一些定时任务,你会怎么做?

    之前的我是这样做的:

    1. 打开chrom
    2. 在github中查找关键字 nodejs 定时任务
    3. 选择star数最高的开源项目.....额,是它 node-schedule。

    然后按照它的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("执行任务");
    
      });
    

    完成代码后,我的心情是这样的。

    呵呵

    但是,老大有一天突然说:你实现的那种方式效率太低了,网上有人用redis实现了定时器。你去看一看,下一版本改为那种实现方式。

    通过查询网上的资料和别人的实现方式,大概整理了如下思路。

    1.Redis 在 2.0.0 之后推出了 Pub / Sub 的指令,可以订阅和发送特定频道消息。
    2.Redis 的 2.8.0 版本之后,其推出了一个新的特性——键空间消息通知(Redis Keyspace Notifications)
    3.就是如果我订阅了键空间消息,那我就可以完成定时任务了。(通知订阅缓存的过期事件,获取对应的key值,使用key值来调用对应任务。 而缓存的过期时间则表示任务的具体执行时间) >.<

    下面是具体实现:

    首先你得保证你的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;
      }
    
    });
    

    其中,我遇到比较大的俩个问题。

    1. 就是时间不好处理,因为不能像之前使用new Date(2015,10,1,0,0,0)这样来设置任务的时间了, 最好用了万能的时间库moment来解决问题

    2. 就是如果你要循环的执行任务。 做法就是你执行一次任务的时候,需要创建下一次任务的缓存。

    相关文章

      网友评论

      • b0cc9207741f:没觉得这种方法比 schedule 高效;
        不过这种方式应该比 schedule 灵活很多!不需要写死时间;
        关于最后的第一点,应该是 redis 不能设置具体的过期时间导致的,可以这样理解吗?
        关于第二点,个人觉得,可以在当次任务执行完成时,自动添加下一次的 redis 缓存;
      • 煮茶听雨:求更多sails的文章
        b0cc9207741f:这里面用到了 sails ?

      本文标题:Nodejs中使用Redis来完成定时任务

      本文链接:https://www.haomeiwen.com/subject/kdlmcttx.html