使用Delayed job处理Rails中的异步任务

转自:http://hi.baidu.com/jiazom/item/37dcc4eb6cc136324cdcaf3a

使用Delayed job处理Rails中的异步任务
git

    Rails cast上有关于介绍Delayed job的使用范例的:使用delayed job处理一个异步发送邮件的任务。我没仔细看。而后本身弄了起来。记录过程以下,但愿给后来者提供一些帮助。github

    首先介绍下应用场景:在WEB应用中,系统执行某些任务时,可能执行结果比较长,而且不须要及时把结果反馈给用户。这样咱们就须要将这些处理时间长的请求剥离成异步处理,及时响应页面的请求。好比Rails cast中示例的发邮件。可能发邮件须要2到10秒钟不等。这个请求若是采用同步处理,会让用户以为卡了一下的感受,体验很差。若是采用异步处理,只须要记录须要处理这个任务,而后将任务记录在某个地方,再由后台程序去调度执行这些任务,这样就能够在极短期(若是其余代码没有问题)内给用户反馈信息,这样体验就会好不少。sql

    个人应用场景是:一个用例在修更名称后,须要将名称同步到脚本相关的Excel中。修改Excel的过程比较长,至少会有3秒以上。这样就须要将这个修改异步出去。个人环境是ruby  + Rails 3 + Mysql。数据库

    在github上搜索delayed job。能够获得好多个分支的delayed job插件。collectiveidea 分支的不错,能够自动创建migration和script任务。ruby

     原理以下:在Object对象上扩展了一个delay方法。若是遇到任何须要异步处理的函数,就使用对象.delay.方法名。好比正常代码为:Mail.send_mail(@mail) ,异步处理即为:Mail.delay.send_mail(@mail)。delay函数中利用ruby的动态性,即将send_mail方法异步调用:先写入到数据库的表delayed_jobs,生成一条记录,worker进程会每隔5秒去检查一下数据库这张表的记录,若是有记录就去读取出来处理掉,而后再删除记录。有点像消息队列的处理机制。废话完毕,开干~~~异步

    一、在Gemfile里面配置:gem 'delayed job'。而后在工程目录下执行:sudo bundle install分布式

    二、执行ruby script/generate delayed_job 。会建立Model和Migration。执行rake db:migration便可创建数据库表。ide

    三、启动worker:ruby scrpt/delayed_job。这个进程就是去定时读取数据库任务的。函数

    四、在须要处理的函数上都加上.delay.方法名。idea

    大功告成。

    有个小问题须要注意:Rails中启动应用会有不一样的环境,为了让delayed_job这个worker找到正确的数据库,须要设置系统的环境变量,执行:export RAILS_ENV=online_production。这样再启动delayed job的worker进程时,就会去读取online_production对应的数据库。

      delayed_job值得说起的特性就是自动重试功能。若是一个方法抛出了异常,这个异常会被捕获,以后这个方法将会从新运行。这个过程最多重复25次,次数越多重试的时间间隔就越长。

     在分布式中,worker进程只须要启动一个便可。不须要每一个机器都启动worker去读取数据库的任务去执行。在异步任务不是太多时,一个进程彻底够用。而且,时间瓶颈也并不是在一个进程仍是在两个进程上,主要仍是在处理异步任务的代码上。另外,须要说明的是,worker启动时能够指定多个实例。还有其余一些参数,运行:ruby script/delayed_job能够看到帮助。