Rails控制器中的Process.fork

时间:2010-10-21 06:12:09

标签: ruby-on-rails ruby ruby-on-rails-3

我们正在对一个新应用进行一些原型设计,并注意到其中一个动作需要永远加载(80-120秒)。由于很多处理不需要在页面加载时发生(我们可以通过Ajax稍后请求数据),我想到使用Process.fork来允许页面立即返回,而处理仍然发生在“后面”场景。“

我们正在将Apache与Passenger一起用于该应用程序。

有几件事:

  1. 我了解delayed_jobs,resque,BJ和其他后台工作宝石。我们使用dj,最终也会使用类似的东西。在我们进行原型设计时,这是一个权宜之计。

  2. 我不关心服务器性能。该应用程序在自己的服务器上运行,只有少数用户尝试使用它。

  3. 早期测试表明这种方法效果很好,但我想知道使用它是否是个好主意。它会变得可靠吗?如果用户导航到另一个页面或关闭标签/浏览器,分叉过程是否会继续? fork完成后,进程是否会自行终止?

3 个答案:

答案 0 :(得分:5)

取决于“处理”的含义。 通常,如果处理方式使用Rails堆栈,这将不可靠 - 因为请求释放的主进程可能被乘客分配给另一个请求,并且事情可能会出错。 此外,Passenger可能会在某些情况下关闭主进程,从而关闭Rails实例(减少空闲实例池等)。

通常,这可能会导致进程泄漏,意外锁定,竞争条件,关机时的应用程序错误等。

我建议使用在Apache / Passenger堆栈外运行的工作人员,例如使用群集BackgrounDRb或其他解决方案(您提到Resque)。

还有另一个想法,我目前用于我的应用程序的cron作业。对于长时间运行的任务,我的crontab只有少量wget个动作。您可以根据需要使用OpenURI在ruby fork中执行类似的操作。想象一下HTTP应用程序 ping 本身。分叉进程不再需要Rails - 它只是访问任务页面,下一个Passenger服务请求并管理此特殊请求的应用程序实例。

如果Passenger杀死fork的父进程并因此分叉进程 - 另一个Rails实例应该继续处理http请求。

答案 1 :(得分:0)

是的,只要您使用之前经过测试和使用的宝石,它就是可靠的。 DelayedJobs和Spawn(我经常使用)已经存在很长时间了,应该完全符合你的期望。

由于进程在服务器后台运行,如果用户关闭没有客户端附件的选项卡/浏览器,它应该继续正常。当程序完成执行后,它将自行终止并释放内存。

您可以阅读有关这个​​优秀wiki-page分叉的更多信息。作为附注,不要在Rails中使用ruby fork方法,因为这对ActiveRecord不起作用。

答案 2 :(得分:0)

只是想加入,以防google让你来到这里。在乘客> v4.0有一种通过使用“带外工作”来实现这一目标的方法。我将它用于冗长的任务,例如在Sinatra控制器中发送电子邮件,如:

# Your app should tell Passenger about this OOB task, won't run otherwise
headers['X-Passenger-Request-OOB-Work'] = "true"
PhusionPassenger.on_event(:oob_work) do
  # The following line takes a while to run,
  # but won't tie up any http-serving processes
  mail.deliver!
end

可在此处找到相关信息:http://blog.phusion.nl/2013/01/22/phusion-passenger-4-technology-preview-out-of-band-work/

以前,我已尝试使用Process.fork并试图在以后杀死该进程;虽然这实际上是第一部分,但它实际上不会在之后杀死分叉进程,并且Passenger最终会吃掉所有可用内存(正如我在生产系统中精心设计的那样)。显然,无法编程来拯救自己的生命。

希望这有帮助!