Pull to refresh

Comments 15

Упс, каким-то чудом не увидел ваш комент. Прошу прощения
Использовал только Resque, но хотим в одном проекте попробовать Sidekiq.
Возможно вам будет интересно!
delayed_job не использовал сильно, в основном resque.
sidekiq и em-resque это всё хорошо, но пока с postgres не сильно то и дружат к сожалению…
Ну они и не будут дружить.

Resque/Sidekiq изначально сделаны, чтобы использовать редис в качестве бакенда.

Если нужно хранить задачи именно в постгресе — используйте DelayedJob или QueueClassic (она использует PUB/SUB, что может быть на порядок эффективнее)
Помоему Вы не правильно меня поняли.
Тот же em-resque для подключения к базе использует em-synchrony в котором есть только mysql2.
github.com/leftbee/em-postgresql-adapter работает нормально только с ActiveRecord 3.1.x.
Или вы открываете соединение к базе с каждого файбера отдельно?
Да, действительно неправильно понял.
Привет коллеги

Поделюсь и я своим опытом с DJ, на его базы мы писали свой лунапарк фреймворк для фоновой обработки задач. Мы работали со второй веткой и DJ и рельсов, но я глянул третью ветку — суть примерно та же.

Почему мы не стали использовать DJ.
Во-первых, для запуска воркера он использует daemons гем, который у нас страшно глючил. Т.е. воркер не воспринимал команды помереть и плодился при редеплоях. Лечили мы это, лечили, и плюнули в итоге. Свой воркер у нас уже работает на runit.

Во-вторых, DJ использует YAML для сериализации объектов, а YAML — это вообще вещь в себе. Ну т.е. если вам надо что-то простое сериализовать, то нет проблем, но вот попробуйте сериализовать например Exception, и возможно это вас удивит, особенно в не самых последних версиях YAML парсера.

Мы еще немного поигрались с потоками в руби для выполнения распределенных фоновых задач, но быстро поняли, что это бесперспективная тема. По крайней мере на 1.8.7. Тут я с автором полностью согласен.

Несколько замечаний по статье.
DJ на самом деле работает с ActiveRecord объектами следующим образом. Он не сериализует их (т.к. они по большей части не сериализуются из-за замыканий), а сохраняет внутри себя строку вида AR:Model:Id и потом по ID ее ищет во время выполнения. Т.е. если вы в DJ запихнули задачу с моделью и до ее выполнения что-то в ней поменяли, то эти изменения уже попадут в задачу. В любом случае, передать модель в DJ ничуть не затратно.

И запускать несколько воркеров нужно тоже осмысленно. Если ваши задачи работают плотно с базой данных, то может получиться ситуация, когда ваши воркеры встанут друг за другом в ожидании освобождения лока от БД, и тут выигрыша уже не будет. В целом же, воркеры загружают полностью rails-окружение и жрут памяти как полноценный инстанс веб-сервера(монгрель,thin или что там у вас) т.е. я бы советовал вообще под задачи выделять отдельную машину и на ней гонять воркеры. Перекинуть на нее задачи можно или репликацией, или RPC вроде thrift.
Большое спасибо за информацию, не знал, что ActiveRecord сериализуется достаточно эффективно.

Забыл отметить, что обычно background-задачи мы запускаем на отдельных машинах, поэтому иногда позволяем себе запускать количество воркеров большее, чем количество потоков. Используем удалённое соединение к MySQL так как работа с файлами не ведётся.

Дедлоки в MySQL вещь достаточно обычная для Rails-прилоежений и они случаются не только в случае нескольких воркеров, но и просто на высоконагруженных серверах. Решается это обычно вынесением модельной логики из after_save/after_create в after_commit чтобы сделать транзакции как можно быстрее. MySQL, кстати, такие транзакции находит и убивает по истечении заданного времени, так что ничего критичного кроме временной блокировки процессов в этом нет.
при деплое через капистрано использую вот такой костыль для рестарта воркеров

namespace :delayed_job do
  task :myrestart do
    stop
    enforce_stop_delayed_job
    run "cd #{current_path}/ && rake jobs:restart"
    start
  end

  def enforce_stop_delayed_job
    run %Q{
      lsof '#{current_path}/log/delayed_job.log' | awk '/^ruby/ { system("kill " $2) }' ;
      COUNT=1;
      until [ $COUNT -eq 0 ]; do
        COUNT=`lsof '#{current_path}/log/delayed_job.log' | grep '^ruby' |wc -l` ;
        echo 'waiting for delayed_job to end' ;
        sleep 2 ;
      done
    }.split("\n").join('')
  end
end

Это некрасиво и килять руби процессы неправильно. Ну правильно, костыль.
Очень удобно пользоваться monit-ом. После настройки в рецепт можно просто добавить следующее:

run "monit restart delayed_job.0 delayed_job.1 delayed_job.2 delayed_job.3"
Иногда демоны не хотят останавливаться. У меня вот resque / god. Так иногда из 30 процессов 1-2 живых остаются после команды stop.
Only those users with full accounts are able to leave comments. Log in, please.