2009-05-22 39 views
28

当创建一个新的资源,它需要做一些冗长处理前的资源准备好了,我怎么发送处理掉到背景不会托起当前请求或其他流量到我的网络应用程序?Ruby on Rails:如何在后台运行事物?

在我的模型

class User < ActiveRecord::Base 
after_save :background_check 

protected 
def background_check 
    # check through a list of 10000000000001 mil different 
    # databases that takes approx one hour :) 
    if(check_for_record_in_www(self.username)) 
    # code that is run after the 1 hour process is finished. 
    user.update_attribute(:has_record) 
    end 
end 
end 

回答

39

你一定要看看下面的Railscasts:

他们解释如何在每一个可能的运行Rails的后台进程方式(有或没有aq ueue ...)

+2

这些天来,最常用的/支持的最好的选择是[sidekiq(https://github.com/mperham/sidekiq),[resque ](https://github.com/defunkt/resque)和[delayed_job](https://github.com/collectiveidea/delayed_job)。恕我直言,Sidekiq是高吞吐量队列的最佳选择,而delayed_job是吞吐量非常低的最佳选择。 – 2013-01-29 03:02:50

7

启动一个单独的进程,这可能是与system最容易做的前面加上一个“nohup的”和附加“&”来给它传递命令的结束。 (确保命令只是一个字符串参数,而不是参数列表。)

有你想要做这种方式,而不是说有几个原因,尝试使用线程:

  1. 当谈到I/O时,Ruby的线程可能有点棘手;你必须注意你所做的一些事情并不会导致整个过程被阻塞。

  2. 如果你运行一个不同名字的程序,它很容易在'ps'中识别出来,所以你不会意外地认为它是一个FastCGI后台疯狂或者什么的,并且杀了它。

真的,您开始的过程应该是“deamonized”,请参阅Daemonize类的帮助。

2

你最好想使用现有的后台作业服务器,而不是自己写。这些通常会让你提交一份工作,并给它一个独特的关键;然后您可以使用该键来定期查询作业服务器的工作状态,而不会阻止您的Web应用程序。 here is a nice roundup在那里的各种选项。

0

什么:

def background_check 
    exec("script/runner check_for_record_in_www.rb #{self.username}") if fork == nil 
end 

程序“check_for_record_in_www.rb”,那么将在另一个进程中运行,将有机会获得的ActiveRecord,能够访问数据库。

1

我喜欢使用backgroundrb,它的好处是它允许你在长时间处理过程中与它通信。所以你可以在你的Rails应用中进行状态更新

1

我认为spawn是一个很好的方式来分叉你的进程,在后台做一些处理,并向用户显示一些确认这个进程已经开始。

6

我刚刚试用'delayed_job'宝石,因为它可以与Heroku托管平台一起使用,并且它的设置非常容易!

将Gem添加到Gemfile中,bundle install,rails g delayed_job,rake db:migrate 然后启动一个队列处理程序;

RAILS_ENV=production script/delayed_job start 

如果你有一个方法调用哪个是你漫长的过程,即

company.send_mail_to_all_users 

你改变它;

company.delay.send_mail_to_all_users 

检查github上完整的文档:https://github.com/collectiveidea/delayed_job