delay异步处理
Rails cast上有关于介绍Delayed job的使用范例的:使用delayed job处理一个异步发送邮件的任务。我没仔细看。然后自己弄了起来。记录过程如下,希望给后来者提供一些帮助。
首先介绍下应用场景:在WEB应用中,系统执行某些任务时,可能执行结果比较长,并且不需要及时把结果反馈给用户。这样我们就需要将这些处理时间长的请求剥离成异步处理,及时响应页面的请求。比如Rails cast中示例的发邮件。可能发邮件需要2到10秒钟不等。这个请求如果采用同步处理,会让用户觉得卡了一下的感觉,体验不好。如果采用异步处理,只需要记录需要处理这个任务,然后将任务记录在某个地方,再由后台程序去调度执行这些任务,这样就可以在极短时间(如果其他代码没有问题)内给用户反馈信息,这样体验就会好很多。
我的应用场景是:一个用例在修改名称后,需要将名称同步到脚本相关的Excel中。修改Excel的过程比较长,至少会有3秒以上。这样就需要将这个修改异步出去。我的环境是ruby ee + Rails 3 + Mysql。
在github上搜索delayed job。可以得到好多个分支的delayed job插件。collectiveidea 分支的不错,可以自动建立migration和script任务。
原理如下:在Object对象上扩展了一个delay方法。如果遇到任何需要异步处理的函数,就使用对象.delay.方法名。比如正常代码为:Mail.send_mail(@mail) ,异步处理即为:Mail.delay.send_mail(@mail)。delay函数中利用ruby的动态性,即将send_mail方法异步调用:先写入到数据库的表delayed_jobs,生成一条记录,worker进程会每隔5秒去检查一下数据库这张表的记录,如果有记录就去读取出来处理掉,然后再删除记录。有点像消息队列的处理机制。废话完毕,开干~~~
1、在Gemfile里面配置:gem 'delayed job'。然后在工程目录下执行:sudo bundle install
2、执行ruby script/generate delayed_job 。会创建Model和Migration。执行rake db:migration即可建立数据库表。
3、启动worker:ruby scrpt/delayed_job。这个进程就是去定时读取数据库任务的。
4、在需要处理的函数上都加上.delay.方法名。
大功告成。
有个小问题需要注意:Rails中启动应用会有不同的环境,为了让delayed_job这个worker找到正确的数据库,需要设置系统的环境变量,执行:export RAILS_ENV=online_production 。这样再启动delayed job的worker进程时,就会去读取online_production对应的数据库。
delayed_job值得提及的特性就是自动重试功能。如果一个方法抛出了异常,这个异常会被捕获,之后这个方法将会重新运行。这个过程最多重复25次,次数越多重试的时间间隔就越长。
在分布式中,worker进程只需要启动一个即可。不需要每个机器都启动worker去读取数据库的任务去执行。在异步任务不是太多时,一个进程完全够用。并且,时间瓶颈也并非在一个进程还是在两个进程上,主要还是在处理异步任务的代码上。另外,需要说明的是,worker启动时可以指定多个实例。还有其他一些参数,运行:ruby script/delayed_job可以看到帮助。
转载自:http://www.myexception.cn/ai/844431.html