Rake задачи и рельсы инициализаторы

Вроде новичок в 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, я ссылаюсь на: среду. Если я поставлю хотя бы одного рабочего динамо в фоновом режиме на героку, мой 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

Некоторое время кажется, что все работает потрясающе... тогда процесс граблей просто перестает подниматься из очереди необъяснимым образом. Очередь становится все больше и больше. Даже если у меня работает несколько рабочих динамов, все они со временем устают и перестают обрабатывать очередь. Я не уверен, что я делаю неправильно, но я подозреваю, что ссылка на среду Rails в моей задаче rake вызывает повторный запуск кода task_scheduler.rb, что приводит к дублированию расписаний. Мне интересно, как решить эту проблему, если кто-то знает, и мне также любопытно, не является ли это причиной прекращения работы граблей.

Спасибо

2 ответа

Решение

Вы не должны загружать планировщик в инициализаторе, у вас должен быть процесс-демон, запускающий планировщик и заполняющий вашу очередь. Это было бы что-то вроде этого ("скрипт / планировщик"):

#!/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, а не по одному на каждого монгрела, который вы запускаете.

Прежде всего, если вы не работаете на Heroku, я бы не рекомендовал такой подход. Я бы посмотрел на ответ Маурисио или подумал бы о том, чтобы использовать классическую работу cron или использовать Whenever для планирования работы cron.

Но если вам больно бегать на героку и пытаться сделать это, вот как я заставил это работать.

Я сохранил тот же оригинальный код 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
    

    Я не уверен, почему, но когда я это убрал, он больше никогда не зависал.

Другие вопросы по тегам