31

当创建新资源并且需要在资源准备好之前进行一些冗长的处理时,我如何将该处理发送到不会阻止当前请求或其他流量到我的网络应用程序的后台?

在我的模型中:

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
4

7 回答 7

42

您绝对应该查看以下 Railscast:

他们解释了如何以各种可能的方式在 Rails 中运行后台进程(有或没有队列......)

于 2009-05-22T14:38:27.423 回答
8

我一直在尝试使用“delayed_job” gem,因为它可以与 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

于 2011-03-11T03:08:51.920 回答
7

启动一个单独的进程,这可能是最容易完成的system,在您传递的命令的末尾添加一个“nohup”并附加一个“&”。(确保命令只是一个字符串参数,而不是参数列表。)

您想这样做有几个原因,而不是尝试使用线程:

  1. 在进行 I/O 时,Ruby 的线程可能有点棘手。您必须注意您所做的某些事情不会导致整个过程阻塞。

  2. 如果你用不同的名字运行一个程序,它很容易在“ps”中识别出来,所以你不会意外地认为它是一个 FastCGI 后端失控或什么的,然后杀死它。

实际上,您启动的进程应该是“去魔化的”,请参阅Daemonize类以寻求帮助。

于 2009-05-22T12:44:31.710 回答
2

理想情况下,您希望使用现有的后台作业服务器,而不是自己编写。这些通常会让你提交一份工作并给它一个唯一的密钥;然后,您可以使用该密钥定期向作业服务器查询您的作业状态,而不会阻止您的 web 应用程序。这是对各种选项的一个很好的总结。

于 2009-05-22T12:57:44.350 回答
1

我喜欢使用 backgroundrb,它很好,它可以让你在长时间的过程中与它进行通信。因此,您可以在 Rails 应用程序中获得状态更新

于 2009-05-22T16:26:14.450 回答
1

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

于 2010-03-29T14:47:38.700 回答
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,从而能够访问数据库。

于 2009-05-22T12:58:25.067 回答