2017-02-02 4 views
8

У меня есть подозрение, что некоторые наши активные рабочие места исчезают, но я не знаю почему. Ниже я нашел доказательства исчезновения, но не причина.Что может привести к исчезновению запланированных Rails Active Jobs?

Наш сайт использует внешнюю службу облачной печати. Мы снимаем задания, а затем проверяем их статус. После успешного создания удаленной облачной печати мы создаем активное задание для немедленного проверки состояния. Если он закончен (успешно или иначе), он помечается как таковой. Если нет, то задание статуса проверки создает другое, с небольшой задержкой. Задержка увеличивается каждый раз.

Одна проверка состояния сегодня, журналы показывают, что ожидание достигло 128 секунд. Но следующая проверка статуса не произошла, и ошибок в журнале тоже нет.

Мы используем активную работу, поддерживаемую отложенной работой. Код для задания проверки состояния приведен ниже. Он не видит недостатков в логике, которые не приведут ни к правильной проверке статуса, ни к другой попытке с ожиданием.

class CheckCloudPrintStatusJob < ApplicationJob 
    queue_as :default 

    def perform(cloud_print, count = 0) 
    cloud_print.update_status 

    unless cloud_print.finished? 
     count += 1 
     wait = 2**(count-1) 

     if count > 15 
     cloud_print.mark_as_failed 

     puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 
     puts "~~~~~~~~~~~~~~~~~~ Cloud printing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 
     puts "Cloud print ##{cloud_print.id} failed" 
     puts "Finally waited #{wait} seconds and then cancelled." 
     puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 
     else 
     puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 
     puts "~~~~~~~~~~~~~~~~~~ Cloud printing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 
     puts "Checking status of cloud print ##{cloud_print.id}" 
     puts "Waiting #{wait} seconds and then retrying." 
     puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 

     CheckCloudPrintStatusJob.set(wait: wait.seconds).perform_later(cloud_print, count) 
     end 
    end 
    end 
end 
+0

, что происходит, когда 'update_status' выдает ошибку? можете ли вы также использовать код в 'update_status'? –

ответ

4

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

Я проверил, что ваш код задания успешно ведет себя за пределы 128-секундной паузой со следующей установкой:

  • rails new проекта
  • delayed_job_active_record добавлен в Gemfile (бег bundle install)
  • rails generate delayed_job:active_record и rake db:migrate для установки драгоценных камней и создания таблицы замедленной работы
  • config.active_job.queue_adapter = :delayed_job в config/application.rb
  • основной CloudPrint < ApplicationRecord модель с update_status, finished? и mark_as_failed методов в app/models/cloud_print.rb
  • предоставленный код в app/jobs/check_cloud_print_status_job.rb
  • Enqueuing работу, запустив CheckCloudPrintStatusJob.perform_later(CloudPrint.create) через Rails консоли (bin/rails c)

Поскольку выше последовательности вел себя правильно без каких-либо проблем, вам нужно расширить свой поиск, предоставив более complete and verifiable example, который фактически воспроизводит проблему. Либо загрузите весь проект Rails в репозиторий GitHub, как только вы сможете последовательно воспроизводить свою проблему или исследовать другие аспекты вашей среды и конфигурации проекта.Вот некоторые возможности:

  • В вашем классе моделей может быть логика, которая могла бы вызвать любые исключения;
  • Демон рабочего-обработчика мог быть прерван или убит;
  • Очередь заданий могла быть очищена (например, через rake jobs:clear)
  • Другой процесс мог модифицировать и/или удалять обрабатываемый объект модели;
  • finished? мог бы вернуть true после того, как update_status был вызван, в результате чего окончательная проверка статуса не была напечатана, даже если обработка завершена успешно.

N.B. - Задержка задания поддерживает повтор неудачных заданий с задержкой 5 seconds + N ** 4, где N - это количество попыток, нет необходимости повторно реализовывать эту логику самостоятельно. Просто raise исключение, если cloud_print.finished? ложно, и вам не требуется какой-либо другой пользовательский код задержки:

class CheckCloudPrintStatusJob < ApplicationJob 
    queue_as :default 

    def perform(cloud_print) 
    raise 'Not ready' unless cloud_print.finished? 
    end 
end 
+0

Спасибо за всеобъемлющий отзывчивый. Хотя ваш ответ прямо не разрешил проблему для нас, было полезно заставить нас задуматься о том, где еще может быть проблема. Как ни странно, решение, похоже, было (помимо добавления дополнительной дополнительной безопасности) переключиться с dj на sidekiq. Ясно, что это не должно иметь значения, но, по-видимому, это так. – Simmo

0

Как вытекает из кода задания, аргумент cloud_print является экземпляром некоторого класса Ruby (кажется ActiveRecord :: Base). Это не очень хорошая идея в целом иметь сложные объекты в качестве аргументов для фоновой работы, потому что эти аргументы должны быть сериализованы в строку, json или yaml. DelayedJob использует YAML-сериализованные объекты, и иногда может быть невозможно восстановить экземпляр модели. Например, если отложенное задание выполняется как обратный вызов before_create - объект модели не был сохранен и не может быть восстановлен. Более подробную информацию можно найти здесь https://github.com/collectiveidea/delayed_job/wiki/Common-problems#jobs-are-silently-removed-from-the-database

+3

Поскольку Rails 5 (по крайней мере), ActiveJob использовать GlobalId при прохождении ActiveModel , как описано здесь http://guides.rubyonrails.org/active_job_basics.html#globalid Это означает, что мы можем передать объект ActiceRecord, и он будет хранить Class + Id и не сериализовать атрибуты объекта. Мы по-прежнему должны заботиться о проблеме after_create с транзакциями – tal

Смежные вопросы