在Rails中组织工作进程的最佳方法是什么?

时间:2009-07-09 02:55:47

标签: ruby-on-rails queue backgroundworker

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

组织这个的好方法是什么?为什么?如果您想使用特定的插件或gem,请解释为什么您觉得它很方便 - 不要只列出您使用的插件。

4 个答案:

答案 0 :(得分:8)

我真的不喜欢像delayed_jobbackground_job那样为了运行异步作业而持久保存到数据库的宝石。它对我来说似乎很脏。瞬态内容不属于数据库。

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

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

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

关于Rails环境,嗯,这可能最好留给读者练习,因为内存使用将成为长期运行过程的一个重要因素。您不想加载任何您不需要的东西。顺便说一下,这是DataMapper在ActiveRecord屁股上狠狠踢的一个区域。环境初始化已有详细记录,并且发现的依赖关系更少,使整个工具包和cabo​​odle更加真实。

我不喜欢cron + rake的一件事是rake几乎可以保证打印到标准输出,如果你的cron作业产生输出,cron往往过于繁琐。我喜欢将所有的cron任务放在一个适当命名的目录中,然后创建一个包装它们的rake任务,这样手动运行它们是微不足道的。 rake这样做很遗憾,因为我真的更愿意选择利用依赖关系。无论如何,你只需将cron直接指向脚本而不是通过cron运行它们。

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

答案 1 :(得分:5)

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

就我而言,我使用了background_jobdelayed_job。使用background_job,工作人员通过cron继续运行,因此没有守护程序管理。使用delayed_job,我正在使用Heroku并让他们担心。

使用delayed_job,您可以传入与后台工作者需要运行的一样多的参数。

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

除了通过cron使用script/runner之外,我还没有找到按计划运行内容的好解决方案(我更喜欢使用script/runner而不是Rake任务,因为我发现测试代码更容易)。

我从来没有必要定期安排后台进程需要访问特定的Rails请求,因此这不是太大的问题。

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

答案 2 :(得分:2)

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

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

我见过Ryan Bates在Starling and Workling的视频直播,他们看起来很有希望,但我还没有使用它们。

答案 3 :(得分:0)

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