Ruby-on-rails Rails App 在后台运行长时间任务的最佳实践?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/508678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:56:53  来源:igfitidea点击:

Best practice for Rails App to run a long task in the background?

ruby-on-railsruby

提问by JP Richardson

I have a Rails application that unfortunately after a request to a controller, has to do some crunching that takes awhile. What are the best practices in Rails for providing feedback or progress on a long running task or request? These controller methods usually last 60+ seconds.

我有一个 Rails 应用程序,不幸的是,在向控制器发出请求后,必须进行一些需要一段时间的处理。Rails 中为长期运行的任务或请求提供反馈或进度的最佳实践是什么?这些控制器方法通常持续 60 秒以上。

I'm not concerned with the client side... I was planning on having an Ajax request every second or so and displaying a progress indicator. I'm just not sure on the Rails best practice, do I create an additional controller? Is there something clever I can do? I want answers to focus on the server side using Rails only.

我不关心客户端......我计划每隔一秒左右就有一个 Ajax 请求并显示一个进度指示器。我只是不确定 Rails 的最佳实践,我要创建一个额外的控制器吗?有什么聪明的我可以做吗?我希望答案只集中在使用 Rails 的服务器端。

Thanks in advance for your help.

在此先感谢您的帮助。

Edit:

编辑:

If it matters, the http request are for PDFs. I then have Rails in conjunction with Ruport generate these PDFs. The problem is, these PDFs are very large and contain a lot of data. Does it still make sense to use a background task? Let's assume an average PDF takes about one minute to two minutes, will this make my Rails application unresponsive to any other server request during this time?

如果重要的话,http 请求是针对 PDF 的。然后我让 Rails 与 Ruport 一起生成这些 PDF。问题是,这些 PDF 非常大并且包含大量数据。使用后台任务还有意义吗?让我们假设平均 PDF 需要大约一分钟到两分钟,这是否会使我的 Rails 应用程序在这段时间内对任何其他服务器请求无响应?

Edit 2:

编辑2:

Ok, after further investigation, it seems my Rails application is indeed unresponsive to any other HTTP requests after a request comes in for a large PDF. So, I guess the question now becomes: What is the best threading/background mechanism to use?It must be stable and maintained. I'm very surprised Rails doesn't have something like this built in.

好的,经过进一步调查,似乎我的 Rails 应用程序在请求进入大型 PDF 后确实对任何其他 HTTP 请求没有响应。 所以,我想现在的问题变成了:最好的线程/后台机制是什么?它必须是稳定和维护的。我很惊讶 Rails 没有内置这样的东西。

Edit 3:

编辑3:

I have read this page: http://wiki.rubyonrails.org/rails/pages/HowToRunBackgroundJobsInRails. I would love to read about various experiences with these tools.

我已阅读此页面:http: //wiki.rubyonrails.org/rails/pages/HowToRunBackgroundJobsInRails。我很想了解使用这些工具的各种经验。

Edit 4:

编辑4:

I'm using Passenger Phusion "modrails", if it matters.

如果重要的话,我正在使用Passenger Phusion“modrails”。

Edit 5:

编辑5:

I'm using Windows Vista 64 bit for my development machine; however, my production machine is Ubuntu 8.04 LTS. Should I consider switching to Linux for my development machine? Will the solutions presented work on both?

我的开发机器使用的是 Windows Vista 64 位;但是,我的生产机器是 Ubuntu 8.04 LTS。我应该考虑为我的开发机器切换到 Linux 吗?提出的解决方案对两者都有效吗?

采纳答案by pantulis

The Workling pluginallow you to schedule background tasks in a queue (they would perform the lengthy task). As of version 0.3 you can ask a worker for its status, this would allow you to display some nifty progress bars.

Workling插件允许您在队列调度后台任务(它们将执行冗长的任务)。从 0.3 版本开始,您可以询问工作人员的状态,这将允许您显示一些漂亮的进度条。

Another cool feature with Workling is that the asynchronous backend can be switched: you can used DelayedJobs, Spawn (classic fork), Starling...

Workling 的另一个很酷的功能是可以切换异步后端:您可以使用 DelayedJobs、Spawn(经典分支)、Starling...

回答by Sarah Mei

I have a very large volume site that generates lots of large CSV files. These sometimes take several minutes to complete. I do the following:

我有一个非常大的站点,可以生成大量的大型 CSV 文件。这些有时需要几分钟才能完成。我执行以下操作:

  • I have a jobs table with details of the requested file. When the user requests a file, the request goes in that table and the user is taken to a "jobs status" page that lists all of their jobs.
  • I have a rake task that runs all outstanding jobs (a class method on the Job model).
  • I have a separate install of rails on another box that handles these jobs. This box just does jobs, and is not accessible to the outside world.
  • On this separate box, a cron job runs all outstanding jobs every 60 seconds, unless jobs are still running from the last invocation.
  • The user's job status page auto-refreshes to show the status of the job (which is updated by the jobs box as the job is started, running, then finished). Once the job is done, a link appears to the results file.
  • 我有一个工作表,其中包含所请求文件的详细信息。当用户请求一个文件时,请求进入该表,并且用户被带到一个列出他们所有工作的“工作状态”页面。
  • 我有一个运行所有未完成作业的 rake 任务(作业模型上的类方法)。
  • 我在另一个处理这些工作的盒子上单独安装了导轨。这个盒子只做工作,外界无法访问。
  • 在这个单独的框中,cron 作业每 60 秒运行一次所有未完成的作业,除非作业从上次调用开始仍在运行。
  • 用户的作业状态页面会自动刷新以显示作业状态(在作业启动、运行和完成时由作业框更新)。作业完成后,将出现一个指向结果文件的链接。

It may be too heavy-duty if you just plan to have one or two running at a time, but if you want to scale... :)

如果你只是计划一次运行一两个,它可能太繁重了,但是如果你想扩展...... :)

回答by Sarah Mei

Calling ./script/runner in the background worked best for me. (I was also doing PDF generation.) It seems like the lowest common denominator, while also being the simplest to implement. Here's a write-up of my experience.

在后台调用 ./script/runner 对我来说效果最好。(我也在做 PDF 生成。)这似乎是最小的公分母,同时也是最容易实现的。 这是我的经验的记录

回答by John Topley

A simple solution that doesn't require any extra Gems or plugins would be to create a custom Rake task for handling the PDF generation. You could model the PDF generation process as a state machine with states such as submitted, processingand completethat are stored in the model's database table. The initial HTTP request to the Rails application would simply add a record to the table with a submittedstate and return.

一个不需要任何额外 Gems 或插件的简单解决方案是创建一个自定义 Rake 任务来处理 PDF 生成。您可以将 PDF 生成过程建模为状态机,其中包含存储在模型数据库表中的提交处理完成等状态。对 Rails 应用程序的初始 HTTP 请求将简单地将记录添加到表中并提交状态并返回。

There would be a cron job that runs your custom Rake task as a separate Ruby process, so the main Rails application is unaffected. The Rake task can use ActiveRecord to find all the models that have the submittedstate, change the state to processingand then generate the associated PDFs. Finally, it should set the state to complete. This enables your AJAX calls within the Rails app to monitor the state of the PDF generation process.

将有一个 cron 作业将您的自定义 Rake 任务作为单独的 Ruby 进程运行,因此主 Rails 应用程序不受影响。Rake 任务可以使用 ActiveRecord 查找所有具有提交状态的模型,将状态更改为处理,然后生成关联的 PDF。最后,它应该将状态设置为complete。这使您在 Rails 应用程序中的 AJAX 调用能够监视 PDF 生成过程的状态。

If you put your Rake task within your_rails_app/lib/tasksthen it has access to the models within your Rails application. The skeleton of such a pdf_generator.rakewould look like this:

如果您将 Rake 任务放在your_rails_app/lib/tasks 中,则它可以访问您的 Rails 应用程序中的模型。这种pdf_generator.rake的骨架看起来像这样:

namespace :pdfgenerator do
  desc 'Generates PDFs etc.'
  task :run => :environment do

    # Code goes here...
  end
end

As noted in the wiki, there are a few downsides to this approach. You'll be using cron to regularly create a fairly heavyweight Ruby process and the timing of your cron jobs would need careful tuning to ensure that each one has sufficient time to complete before the next one comes along. However, the approach is simple and should meet your needs.

正如维基中所指出的,这种方法有一些缺点。您将使用 cron 定期创建一个相当重量级的 Ruby 进程,并且您的 cron 作业的时间安排需要仔细调整,以确保每个作业都有足够的时间在下一个作业出现之前完成。但是,该方法很简单,应该可以满足您的需求。

回答by RajG

This looks quite an old thread. However, what I have down in my app, which required to run multiple Countdown Timersfor different pages, was to use Ruby Thread. The timer must continue running even if the page was closed by users.

Ruby makes it easy to write multi-threaded programs with the Thread class. Ruby threads are a lightweight and efficient way to achieve parallelism in your code.I hope this will help other wanderers who is looking to achieve background: parallelism/concurrent services in their app. Likewise Ajax makes it a lot easier to call a specific Rails [custom] action every second.

这看起来很旧的线程。但是,我在我的应用程序中需要为不同的页面运行多个倒数计时器的功能是使用Ruby Thread。即使页面被用户关闭,计时器也必须继续运行。

Ruby 使使用 Thread 类编写多线程程序变得容易。Ruby 线程是一种在代码中实现并行性的轻量级且高效的方式。我希望这会帮助其他希望在他们的应用程序中实现背景:并行/并发服务的流浪者。同样,Ajax 使每秒调用特定的 Rails [自定义] 操作变得更加容易。

回答by scaryguy

I recommend using Resquegem with it's resque-statusplug-in for your heavy background processes.

我建议将Resquegem 与它的resque-status插件一起用于繁重的后台进程。

Resque

请求

Resque is a Redis-backed Ruby library for creating background jobs, placing them on multiple queues, and processing them later.

Resque 是一个 Redis 支持的 Ruby 库,用于创建后台作业,将它们放在多个队列中,并在以后处理它们。

Resque-status

请求状态

resque-status is an extension to the resque queue system that provides simple trackable jobs.

resque-status 是 resque 队列系统的扩展,提供简单的可跟踪作业。

Once you run a job on a Resque worker using resque-status extension, you will be able to get info about your ongoing progresses and ability to kill a specific process very easily. See examples:

一旦您使用 resque-status 扩展在 Resque worker 上运行作业,您将能够非常轻松地获取有关正在进行的进度和终止特定进程的能力的信息。请参阅示例:

status.pct_complete #=> 0
status.status #=> 'queued'
status.queued? #=> true
status.working? #=> false
status.time #=> Time object        
status.message #=> "Created at ..."

Also resque and resque-status has a cool web interface to interact with your jobs which is so cool.

resque 和 resque-status 也有一个很酷的网络界面来与你的工作进行交互,这太酷了。

回答by zetetic

I'm using Windows Vista 64 bit for my development machine; however, my production machine is Ubuntu 8.04 LTS. Should I consider switching to Linux for my development machine? Will the solutions presented work on both?

我的开发机器使用的是 Windows Vista 64 位;但是,我的生产机器是 Ubuntu 8.04 LTS。我应该考虑为我的开发机器切换到 Linux 吗?提出的解决方案对两者都有效吗?

Have you considered running Linux in a VM on top of Vista?

您是否考虑过在 Vista 之上的 VM 中运行 Linux?

回答by nitecoder

This really does sound like something that you should have a background process running rather than an application instance(passenger/mongrel whichever you use) as that way your application can stay doing what it's supposed to be doing, serving requests, while a background task of some kind, Workling is good, handles the number crunching. I know that this doesn't deal with the issue of progress, but unless it is absolutely essential I think that is a small price to pay.

这确实听起来像是您应该运行后台进程而不是应用程序实例(无论您使用哪种乘客/杂种),因为这样您的应用程序可以继续做它应该做的事情,为请求提供服务,而后台任务某种,Workling 很好,处理数字运算。我知道这与进度问题无关,但除非绝对必要,否则我认为这是一个很小的代价。

You could have a user click the action required, have that action pass the request to the Workling queue, and have it send some kind of notification to the user when it is completed, maybe an email or something. I'm not sure about the practicality of that, just thinking out loud, but my point is that it really seems like that should be a background task of some kind.

您可以让用户单击所需的操作,让该操作将请求传递到工作队列,并在完成时向用户发送某种通知,可能是电子邮件或其他内容。我不确定它的实用性,只是大声思考,但我的观点是这似乎真的应该是某种背景任务。

回答by Orion Edwards

I've used spawnbefore and definitely would recommend it.

我以前用过spawn,肯定会推荐它。

Incredibly simple to set up (which many other solutions aren't), and works well.

设置起来非常简单(许多其他解决方案都没有),并且运行良好。

回答by salt.racer

There is the brand new Growl4Rails... that is for this specific use case (among others as well).

有全新的Growl4Rails......这是针对这个特定用例(以及其他用例)。

http://www.writebetterbits.com/2009/01/update-to-growl4rails.html

http://www.writebetterbits.com/2009/01/update-to-growl4rails.html