【问题标题】:Rake tasks and rails initializersRake 任务和 Rails 初始化器
【发布时间】:2011-10-11 19:31:02
【问题描述】:

对 Rails 有点陌生,所以请配合我。我现在正在做的是后台处理一些使用 Resque 的 Ruby 代码。为了启动 Rescque rake 任务,我一直在使用(在 heroku 上),我有一个 resque.rake 文件,其中包含推荐的代码附加到 heroku 的神奇(或奇怪)线程架构中:

require "resque/tasks"
require 'resque_scheduler/tasks'

task "resque:setup" => :environment do
  ENV['QUEUE'] = '*'
end


desc "Alias for resque:work (To run workers on Heroku)"
task "jobs:work" => "resque:work"

因为我需要访问 Rails 代码,所以我参考 :environment。如果我在 heroku 的背景中设置了至少 1 个工人测功机,我的 Resque 做得很好,被清除了,一切都很开心。直到我尝试自动化的东西......

所以我想改进代码并每隔一分钟左右自动将相关任务填充到队列中。这样做(不使用 cron,因为 heroku 不适合 cron),我声明了一个名为 task_scheduler.rb 的初始化程序,它使用 Rufus 调度程序来运行任务:

scheduler = Rufus::Scheduler.start_new

scheduler.in '5s' do
  autoprocessor_method
end

scheduler.every '1m' do
  autoprocessor_method
end

在一段时间内,一切似乎都很棒......然后 rake 进程就莫名其妙地停止从队列中提取。队列变得越来越大。即使我有多个工人测功机在运行,它们最终都会感到疲倦并停止处理队列。我不确定我做错了什么,但我怀疑我的 rake 任务中对 Rails 环境的引用导致 task_scheduler.rb 代码再次运行,从而导致重复调度。我想知道如果有人知道如何解决这个问题,我也很好奇这是否是 rake 任务停止工作的原因。

谢谢

【问题讨论】:

    标签: ruby-on-rails rake initializer rufus-scheduler


    【解决方案1】:

    您不应该在初始化程序中启动调度程序,您应该有一个守护进程运行调度程序并填满您的队列。它会是这样的(“脚本/调度程序”):

    #!/usr/bin/env ruby
    
    root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
    Dir.chdir(root)
    
    require 'rubygems'
    gem 'daemons'
    require 'daemons'
    
    options = {
        :dir_mode   => :normal,
        :dir        => File.join(root, 'log'),
        :log_output => true,
        :backtrace  => true,
        :multiple   => false
    }
    
    Daemons.run_proc("scheduler", options) do
    
      Dir.chdir(root)
      require(File.join(root, 'config', 'environment'))
    
      scheduler = Rufus::Scheduler.start_new
    
      scheduler.in '5s' do
        autoprocessor_method
      end
    
      scheduler.every '1m' do
        autoprocessor_method
      end
    
    end
    

    您可以在您的应用程序中将此脚本作为普通守护程序调用:

    script/scheduler start
    

    这将确保您只有 一个 进程为 resque 工作人员发送工作,而不是为您正在运行的每个 mongrel 发送工作。

    【讨论】:

    • 感谢您的快速响应毛里西奥。快速跟进,如果我从初始化程序调用此调度程序脚本,我是否会遇到相同的问题,即我的 resque rake 任务调用调度程序并产生另一个进程?如果是这样,建议我在哪里调用调度程序脚本?我需要它在启动时运行。
    • 您不能将其设置为外部进程吗?一个普通的linux守护进程?我真的不知道 Heroku 是如何工作的。
    • 并且您不应该在初始化程序中调用此脚本,因为您可能会遇到与之前相同的问题,因为它会创建许多守护程序而不是一个。
    • 感谢毛里西奥的帮助。如果我可以在 heroku 上设置一个外部进程,这一切都会更容易。但由于我不能,我不得不使用这些其他方式。由于缺乏对后台处理的控制和对数据库的控制,我正在考虑离开 heroku。尽管您的答案在非 Heroku 世界中有效,但我将为那些遇到此问题并在 heroku 上运行的人发布另一个答案。再次感谢!
    【解决方案2】:

    首先,如果您没有在 Heroku 上运行,我不推荐这种方法。我会看看 Mauricio 的回答,或者考虑使用经典的 cron 作业或使用 When 来安排 cron 作业。

    但是,如果您在 Heroku 上运行并尝试执行此操作时感到痛苦,那么我就是这样做的。

    我保留了与原始问题相同的原始 Resque.rake 代码。此外,我创建了另一个附加到作业的 rake 任务:work rake 进程,就像第一个案例一样:

    desc "Scheduler processor"
      task :scheduler => :environment do
      autoprocess_method
      scheduler = Rufus::Scheduler.start_new
      scheduler.every '1m' do
         twitter_autoprocess
      end
    end
    
    desc "Alias for resque:work (To run workers on Heroku)"
    task "jobs:work" => "scheduler"
    

    几个笔记:

    1. 一旦您使用多个工作人员测功机,这将是不完美的,因为调度程序将在多个位置运行。你可以通过在某处保存状态来解决这个问题,但它不像我想要的那样干净。
    2. 我找到了进程挂起的原始原因。就是这行代码:

      scheduler.in '5s' do
       autoprocessor_method
      end
      

      我不知道为什么,但是当我删除它时,它再也没有挂起。

    【讨论】:

    • 它没有再次挂起的部分原来是不正确的。嗯。我开始怀疑这是否是我的代码或 Resque 中的问题。有人有想法吗? Resque 进程多次正常工作,直到它最终停止响应排队的任务。很奇怪。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-16
    • 2011-06-02
    • 2010-10-20
    • 1970-01-01
    • 2015-08-15
    相关资源
    最近更新 更多