2

Kinda new to Rails, so please cope with me. What i'm doing now is background processing some Ruby code use Resque. To get the Rescque rake task started, I've been using (on heroku), I have a resque.rake file with that recommended code to attach into heroku's magical(or strange) threading architecture:

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"

Since I need access to the Rails code, I reference :environment. If I set at least 1 worker dyno in the background on heroku, my Resque does great, gets cleared, everything is happy. Until i try to automate stuff...

So I wanted to evolve the code and automatically fill the queue with relevant tasks every minute or so. Do that (without using cron, because heroku is not adequate with cron), I declare an initializer named task_scheduler.rb that uses Rufus scheduler to run tasks:

scheduler = Rufus::Scheduler.start_new

scheduler.in '5s' do
  autoprocessor_method
end

scheduler.every '1m' do
  autoprocessor_method
end

Things appear to work awesome for a while....then the rake process just stops picking up from the queue unexplainably. The queue just gets larger and larger. Even if i have multiple worker dynos running, they all eventually get tired and stop processing the queue. I'm not sure what I am doing wrong, but I suspect the referencing of the Rails environment in my rake task is causing the task_scheduler.rb code to run again, causing duplicate scheduling. I'm wondering how to solve that problem if someone knows, and I'm also curious if that is the reason for the rake task to stop working.

Thank you

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

これにより、実行中の雑種ごとに 1 つのプロセスではなく、resque ワーカーに作業を送信するプロセスが1 つだけになるようになります。

于 2011-07-23T23:37:09.537 に答える
3

まず、Heroku を使用していない場合、このアプローチはお勧めしません。Mauricio の回答を見るか、従来の cron ジョブを使用するか、Whenever を使用して cron ジョブをスケジュールすることを検討します。

しかし、heroku を実行してこれを実行しようとするのが面倒な場合は、これを機能させる方法を次に示します。

元の質問に貼り付けたのと同じ元の Resque.rake コードをそのまま残しました。さらに、最初のケースと同様に、jobs:work rake プロセスにアタッチする別の 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
    

    理由はわかりませんが、それを削除すると、再びハングすることはありませんでした。

于 2011-07-24T09:45:56.527 に答える