2

对 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 任务停止工作的原因。

谢谢

4

2 回答 2

5

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

#!/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 发送工作。

于 2011-07-23T23:37:09.537 回答
3

首先,如果您不在 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
    

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

于 2011-07-24T09:45:56.527 回答