Rake任务和rails初始化器

时间:2011-07-23 21:13:53

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

有点Rails的新手,所以请对付我。我现在正在做的是后台处理一些Ruby代码使用Resque。为了启动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个工作dyno,我的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

事情看起来有点令人敬畏......然后,佣金流程就会无法解决地从队列中停止。队列越来越大。即使我有多个工作人员dynos在运行,他们最终都会感到疲倦并停止处理队列。我不确定我做错了什么,但我怀疑在我的rake任务中引用Rails环境导致task_scheduler.rb代码再次运行,导致重复调度。我想知道如果有人知道如何解决这个问题,我也很好奇,如果这是rake任务停止工作的原因。

谢谢

2 个答案:

答案 0 :(得分: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 worker发送工作,而不是为您正在运行的每个mongrel发送一个。

答案 1 :(得分:3)

首先,如果你没有在Heroku上运行,我不会推荐这种方法。我会看看Mauricio的答案,或考虑使用经典的cron作业或使用Whenever安排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. 一旦您使用多个工作人员dyno,这将是不完美的,因为调度程序将在多个地点运行。你可以通过在某个地方保存状态来解决这个问题,但它并不像我想的那样干净。
  2. 我找到了进程挂起的原因。就是这行代码:

    scheduler.in '5s' do
     autoprocessor_method
    end
    

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