【问题标题】:What's the best way to organize worker processes in Rails?在 Rails 中组织工作进程的最佳方式是什么?
【发布时间】:2010-11-09 06:04:35
【问题描述】:

我经常有一些代码应该按计划运行或作为带有一些参数的后台进程运行。共同点是它们在调度进程之外运行,但需要访问 Rails 环境(可能还有传入的参数)。

有什么好的方法来组织这个,为什么?如果您喜欢使用特定的插件或 gem,请说明您觉得它方便的原因——不要只列出您使用的插件。

【问题讨论】:

    标签: ruby-on-rails queue backgroundworker


    【解决方案1】:

    我真的不喜欢像 delayed_jobbackground_job 这样为了运行异步作业而持久保存到数据库的 gem。我觉得它很脏。暂时的东西不属于数据库。

    我非常喜欢使用消息队列来处理异步任务,即使您不需要大规模的可扩展性也是如此。在我看来,消息队列是复杂系统的理想“通用语”。在大多数情况下,使用消息队列,您对所构建的任何内容所涉及的技术或语言都没有任何限制。使用低并发消息队列的好处可能在“企业”环境中最为明显,因为集成总是一个巨大的痛苦。此外,当您的异步工作流涉及多个步骤时,消息队列是理想的选择。 RabbitMQ 是我个人的最爱。

    例如,考虑您正在构建搜索引擎的场景。人们可以提交要编入索引的 URI。显然,您不想在请求中检索和索引页面。因此,您围绕消息队列构建:表单提交目标获取 URI,将其放入要索引的消息队列中。下一个可用的蜘蛛进程将 URI 从队列中弹出,检索页面,找到所有链接,如果它们是未知的,则将它们中的每一个推回队列,并缓存内容。最后,一条新消息被推送到第二个队列中,以便索引器进程处理缓存的内容。索引器进程将该消息从队列中弹出,并对缓存的内容进行索引。当然过于简单了——搜索引擎需要做很多工作,但你明白了。

    至于实际的守护进程,显然,我偏爱我自己的库 (ChainGang),但它实际上只是 Kernel.fork() 的一个包装器,它为您提供了一个方便的地方来处理设置和拆卸代码。它还没有完全完成。守护进程远没有消息队列重要,真的。

    关于 Rails 环境,这可能最好留给读者作为练习,因为对于长时间运行的进程而言,内存使用将是一个重要因素。你不想加载任何你不需要的东西。顺便说一句,这是 DataMapper 对 ActiveRecord 的有力打击的一个领域。环境初始化有据可查,影响的依赖项也少了很多,使整个套件和 caboodle 更加逼真。

    我不喜欢 cron+rake 的一件事是,rake 实际上可以保证打印到标准输出,如果您的 cron 作业产生输出,则 cron 往往会过于健谈。我喜欢将我所有的 cron 任务放在一个适当命名的目录中,然后制作一个包装它们的 rake 任务,这样手动运行它们就很简单了。 rake 这样做很可惜,因为我真的更愿意选择利用依赖关系。在任何情况下,您只需将 cron 直接指向脚本,而不是通过 cron 运行它们。

    我目前正在构建一个严重依赖异步进程的网络应用程序,我不得不说,我非常非常高兴我决定不使用 Rails。

    【讨论】:

    • 出于好奇,您决定使用什么?
    • Sinatra、DataMapper、Xapian、RabbitMQ
    • 听起来您在架构上花费的时间比大多数人愿意花费的时间要多得多,或者您的应用程序比通常的应用程序要复杂得多。想法?
    • 我可能不会这么说。有问题的应用程序是一个基本上没有功能的搜索引擎,用于 iPhone 应用程序可以调用的食谱。它有不到 10 个不同的页面,并且可能主要作为 Web 服务访问。绝大多数复杂性在于处理爬取、解析和索引的异步进程。然而,即便如此,它主要还是一堆库,它们之间的胶水代码尽可能少。非典型?确实。但我觉得它是我做过的最优雅的网络应用程序之一。我怀疑这是相关的。
    • @VarunGupta 当然,那是在 2009 年写的。事情发生了变化,这些信息现在基本上已经过时了。尽管它的情绪和理由仍然有效。今天我可能会在心跳中使用 Resque 而不是 RabbitMQ。随意编辑答案。
    【解决方案2】:

    对我来说,不想维护大量额外的基础设施是一个关键的优先事项,所以我使用了在 Rails 之外运行的数据库支持的队列。

    就我而言,我使用了background_jobdelayed_job。使用background_job,worker 通过 cron 保持运行,因此没有守护进程管理。通过delayed_job,我使用 Heroku 并让他们担心。

    使用delayed_job,您可以传递后台工作人员需要运行的任意数量的参数。

    Delayed::Job.enqueue(MyJob.new(param[:one], param[:two], param[:three])
    

    除了通过 cron 使用 script/runner(我更喜欢在 Rake 任务上使用 script/runner,因为我发现测试代码更容易)之外,我还没有找到按计划运行东西的好方法。

    我从来不需要定期安排需要访问特定 Rails 请求的后台进程,所以这不是什么大问题。

    我知道还有其他更酷的系统具有更多功能,但这对我来说效果不错,并帮助我避免设置大量新服务来管理。

    【讨论】:

    • 我想补充一点,虽然 Yehuda 接受了这个答案,但我不认为最适合我的方法是对其他人最好的。作为一个糟糕的系统管理员,我的首要任务是减少系统管理员的任务 :) 如果你有更多的技能或需要更高性能的解决方案,那么一定要尝试一种更深奥的排队系统。
    【解决方案3】:

    我有一个系统接收请求,然后需要使用 Web 服务调用多个外部系统。其中一些请求花费的时间比用户预期的要长,我使用企业排队系统 (activemq) 来处理这些请求。

    我正在使用ActiveMessaging 插件来执行此操作。这使我可以编组请求并将其放在队列中以进行异步处理并访问请求数据,但是如果您想等待响应,则需要编写轮询服务。

    我在Starling and Workling 上看到了 Ryan Bates railscast,它们看起来很有希望,但我没有使用它们。

    【讨论】:

      【解决方案4】:

      对于定期安排的任务,我只使用 rake 任务。它简单、易于测试、易于理解并与 Rails 环境很好地集成。然后只需按照您需要的任何时间间隔使用 cron 作业执行这些 rake 任务(我使用 whenever 来管理这些作业,因为我对 cron 不识字)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-25
        相关资源
        最近更新 更多