【问题标题】:Best practice for Rails App to run a long task in the background?Rails App 在后台运行长时间任务的最佳实践?
【发布时间】:2019-11-10 16:54:04
【问题描述】:

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

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

提前感谢您的帮助。

编辑:

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

编辑 2:

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

编辑 3:

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

编辑 4:

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

编辑 5:

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

【问题讨论】:

  • 关于编辑 5:考虑使用 VirtualBox/Vagrant 进行开发。由于绝大多数开发都是在 unix 机器上完成的,而且您的开发和生产环境可以相同,因此您将省去很多麻烦。
  • @riley - 如果我的生产环境是 CentOS,而我的开发机器运行的是 Linux Mint,该怎么办?我也应该使用虚拟机吗?

标签: ruby-on-rails ruby


【解决方案1】:

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

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

【讨论】:

  • 我会研究它,但我想避免使用 gems/plugins,因为它们中的许多似乎在开发人员感到无聊后停止接受维护。
  • 不幸的是,我认为您必须使用 gem。消息/后台任务队列需要像 Workling 或 Starling 甚至 BackgroundRB 这样的东西。您也可以让 Rake 任务为您完成工作,但我不知道您将如何通知前端。
  • 我以前用过Workling/Starling,会推荐它。不过,您必须运行单独的 Starling 服务器,这很烦人。
  • 如果你想避免 Rails 中的 gems,你会遇到困难的......无论如何,修补 gem 可能比从头开始构建每个单独的组件要容易得多。
【解决方案2】:

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

  • 我有一个包含所请求文件详细信息的作业表。当用户请求文件时,请求会进入该表,然后用户会被带到列出所有作业的“作业状态”页面。
  • 我有一个运行所有未完成作业的 rake 任务(作业模型上的一个类方法)。
  • 我在另一个处理这些工作的盒子上单独安装了导轨。这个盒子只是做工作,外界无法访问。
  • 在这个单独的框中,cron 作业每 60 秒运行一次所有未完成的作业,除非作业从上次调用开始仍在运行。
  • 用户的作业状态页面会自动刷新以显示作业的状态(在作业开始、运行和完成时由作业框更新)。作业完成后,会出现一个指向结果文件的链接。

如果你只打算一次运行一两个,这可能太繁重了,但如果你想扩展...... :)

【讨论】:

    【解决方案3】:

    在后台调用 ./script/runner 对我来说效果最好。 (我也在做 PDF 生成。)它似乎是最小的公分母,同时也是最容易实现的。 Here's a write-up of my experience.

    【讨论】:

    • 哇。其简单性是惊人的!我一定要试试。但是,状态/进度很重要。我想知道尝试并报告状态的最佳方法是什么?也许通过文件??
    • 只需让脚本/运行程序将其进度写入标准输出并从调用代码中捕获。
    【解决方案4】:

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

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

    如果您将 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
    

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

    【讨论】:

      【解决方案5】:

      这看起来是一个很老的线程。然而,我的应用程序需要为不同的页面运行多个 Countdown Timers,而我在应用程序中遇到的问题是使用 Ruby Thread。即使页面被用户关闭,计时器也必须继续运行。

      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. 我希望这将帮助其他希望实现背景的流浪者:在他们的应用程序中实现并行/并发服务。同样,Ajax 使每秒调用特定的 Rails [自定义] 操作变得更加容易。

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

          • 尝试 vagrant,与厨师独奏进行设置。复制生产环境的简单(ish)方法,另外,如果您有任何问题,或者其他人需要相同的服务器,只需重建它就可以了。
          【解决方案8】:

          对于繁重的后台进程,我建议使用 Resque gem 和它的 resque-status 插件。

          回复

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

          请求状态

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

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

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

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

          【讨论】:

            【解决方案9】:

            有全新的 Growl4Rails ... 用于此特定用例(以及其他用例)。

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

            【讨论】:

              【解决方案10】:

              我使用后台作业 (http://codeforpeople.rubyforge.org/svn/bj/trunk/README) 来安排任务。我正在构建一个小型管理站点,它允许站点管理员运行您和我将通过一个漂亮的 Web 界面从命令行运行的各种事情。

              【讨论】:

                【解决方案11】:

                我知道您说过您并不担心客户端,但我认为您可能会觉得这很有趣:Growl4Rails - 从他们使用的示例来看,这些通知几乎是为您正在做的事情而开发的。

                【讨论】:

                  【解决方案12】:

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

                  设置起来非常简单(许多其他解决方案没有),而且效果很好。

                  【讨论】:

                    【解决方案13】:

                    查看BackgrounDRb,它专为您所描述的场景而设计。

                    我认为它已经存在了一段时间并且非常成熟。您可以监控工人的状态。

                    在与生产环境相同的开发平台上进行开发是个好主意,尤其是在使用 Rails 时。在 VM 中运行 Linux 的建议是一个很好的建议。查看 Sun xVM 了解开源虚拟化软件。

                    【讨论】:

                      【解决方案14】:

                      我个人将 active_messaging 插件与 activemq 服务器(stomp 或 rest 协议)一起使用。这对我们来说非常稳定,每月处理数百万条消息。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2014-01-18
                        • 1970-01-01
                        • 2015-08-17
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2017-02-15
                        • 1970-01-01
                        相关资源
                        最近更新 更多