Resque — ruby-библиотека для создания фоновых задач, составления очередей таких задач и их последующего выполнения. Задачи могут быть любым ruby-классом или модулем, содержащим метод perform. В ruby-сообществе Resque пришел на смену Delayed Job (не знаю, кстати, почему проект перестал развиваться, весьма удобная была вещь на мой взгляд) и обладает большим количеством различных преимуществ, таких как разделение задач по разным машинам, приоритеты задач, устойчивость к разным утечкам памяти и еще, и еще, и еще. На этом вступление для тех, кто не может самостоятельно перевести первый абзац из README прошу считать законченным.
В данной статье будет показано как использовать resque и resque-scheduler в rails-приложении.
Подключаем resque в rails-проект
Для использования resque необходимо установить Redis — хранилище данных типа ключа-значение. С установкой проблем возникнуть не должно — пользователи Linux и Mac без труда найдут и исходники, и готовые пакеты, пользователи Windows сами выбрали путь мазохистов также должны справиться. Кроме того установить Redis можно с помощью самого Resque, подробнее об этом на гитхаб-странице проекта. После установки запускается все это простой командой redis-server.
Далее добавляем в Gemfile:
gem ‘resque’
gem ‘resue-scheduler’
Затем bundle install и поехали!
В config/initializers добавляем файл resque.rb примерно с таким содержанием:
uri = URI.parse("redis://localhost:6379/")
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
где 6379 — порт, на котором запускается redis по умолчанию.
Для того, чтобы иметь доступ к нашим фоновым задачам через web-интерфейс, добавляем следующие строки в config.ru:
require 'resque/server'
run Rack::URLMap.new "/" => AppName::Application, "/resque" => Resque::Server.new
и по адресу localhost:3000/resque вы можете увидеть всю необходимую информацию об очередях, задачах, смысле жизни и т.д.
Добавляем rake-таск(уж простите за такой транслит, но “задача” занята job’ом) — создаем файл lib/tasks/resque.rake со следующим содержимым:
require 'resque/tasks'
task "resque:setup" => :environment
и запускаем ее:
rake resque:work QUEUE=*
Теперь в окне терминала вы можете видеть вывод выполняющихся задач.
Базовые функции
Для начала создадим некий класс, который и будет представлять из себя задачу, которую нам нужно выполнить. Перед этим создадим директорию для хранения классов задач, например app/jobs и добавим эту папку в config/initializers/resque.rb:
Dir["#{Rails.root}/app/jobs/*.rb"].each { |file| require file }
Содержимое же класса должно быть примерно таким:
class SimpleJob
@queue = :simple
def self.perform
# здесь делаем важные и полезные вещи
…
…
...
puts "Job is done"
end
end
Обратите внимание на имя очереди — simple, это обязательно, как и метод perform. Добавить эту задачу в очередь можно так: Resque.enqueue(SimpleJob). Результат выполнения, строка “Job is done” будет выведена в консоль resque, кроме того по адресу localhost:3000/resque можно увидеть новую добавленную очередь и результат работы воркера.
Передать аргументы в perform также не составляет труда. Например изменяем наш класс следующим образом:
def self.perform(str)
# здесь делаем важные и полезные вещи
…
…
...
puts "Job is done! #{str}"
end
И добавляем задачу в очередь следующим образом: Resque.enqueue(SimpleJob, “Yahoo!”). После перезпуска rake resque:work QUEUE=* в консоли вы увидите ожидаемое: “Job is done! Yahoo!”. Следует отметить, что все аргументы передаваемые через enqueue сериализуются в JSON, из-за чего объекты класса Symbol становятся обычными строками, а сложные объекты, например сущности ActiveRecord — хэшами. Соответственно, если вы хотите использовать методы и ассоциации ваших моделей, есть смысл передавать просто id объектов и выбирать их уже внутри perform.
Планировщик задач
Resque-scheduler — расширение Resque для задач, которые должны быть выполнены в будущем. Он поддерживает два типа задач — задержанные и задачи по расписанию. Добавим scheduler в наш проект. Добавляем конфигурацию scheduler в resque.rake, теперь он выглядит так:
require 'resque/tasks'
require 'resque_scheduler/tasks'
task "resque:setup" => :environment
namespace :resque do
task :setup do
require 'resque'
require 'resque_scheduler'
require 'resque/scheduler'
Resque.redis = 'localhost:6379'
Resque.schedule = YAML.load_file("#{Rails.root}/config/rescue_schedule.yml")
end
end
Как видно из этого участка кода, мы грузим расписание из файла config/rescue_schedule.yml:
every_two_minute_job:
cron: "*/2 * * * *"
class: SimpleTask
args: some arg
description: “every two minute job”
Для использования scheduler в rails-приложении нужно также добавить в config/initializers/resque.rb строку require 'resque_scheduler'
Теперь запускаем в консоли rake resque:scheduler и смотрим, как наша задача выполняется каждые 2 минуты. Добавлять задержанные задачи еще проще:
Resque.enqueue_at(2.minutes.from_now, SimpleTask, ‘some arg’)
чтобы выполнить задачу в определенное время,
Resque.enqueue_in(2.minutes, SimpleTask, ‘some arg’)
чтобы выполнить задачу через определенное время.
Также можно удалять добавленные задержанные задачи:
Resque.remove_delayed(SimpleTask, ‘some arg’)
Конечно же работу Resque можно и нужно тестировать, для этого есть соответствующие gem’ы:
github.com/leshill/resque_spec
github.com/justinweiss/resque_unit
Дополнительные ссылки
Код Resque на гитхабе
github.com/defunkt/resque
Resque-scheduler там же
github.com/bvandenbos/resque-scheduler
Документация онлайн
defunkt.io/resque/
Скринкаст от Райана Бэйтса
railscasts.com/episodes/271-resque
Гостевая статья Дэйва Хувера для RubyLearning Blog
rubylearning.com/blog/2010/11/08/do-you-know-resque/
Jon Homan — Background Jobs in Rails with Resque
blog.jonhoman.com/background-jobs-in-rails-with-resque/
Allen Fair — Understanding how Resque works
girders.org/resque-internals-for-heterogenous-systems
Автор: rsludge