module ActiveJob::Exceptions::ClassMethods
Публичные методы экземпляра
# File activejob/lib/active_job/exceptions.rb, line 131 def after_discard(&blk) self.after_discard_procs += [blk] end
Блок, который выполняется, когда задача собирается быть отброшена по любой причине.
Пример
class WorkJob < ActiveJob::Base
after_discard do |job, exception|
ExceptionNotifier.report(exception)
end
...
end # File activejob/lib/active_job/exceptions.rb, line 109
def discard_on(*exceptions, report: false)
rescue_from(*exceptions) do |error|
instrument :discard, error: error do
ActiveSupport.error_reporter.report(error, source: "application.active_job") if report
yield self, error if block_given?
run_after_discard_procs(error)
end
end
end Отбросить задачу без попыток повторного выполнения, если возникает исключение. Это полезно, когда объект, связанный с задачей, например Active Record, больше недоступен, и задача, таким образом, теряет актуальность.
Передача параметра :report приводит к тому, что ошибка перед отбрасыванием задачи передаётся системе отчётов об ошибках.
Можно также передать блок, который будет вызван. Блоку передаются экземпляр задачи в качестве первого параметра и экземпляр ошибки в качестве второго.
Обработчики retry_on и discard_on ищутся снизу вверх, а затем вверх по иерархии классов. Если таковой имеется, вызывается обработчик первого класса, для которого выполняется условие exception.is_a?(klass).
Пример
class SearchIndexingJob < ActiveJob::Base
discard_on ActiveJob::DeserializationError
discard_on CustomAppException, report: true
discard_on(AnotherCustomAppException) do |job, error|
CustomErrorHandlingCode.handle(job, error)
end
def perform(record)
# Will raise ActiveJob::DeserializationError if the record can't be deserialized
# Might raise CustomAppException for something domain specific
end
end
# File activejob/lib/active_job/exceptions.rb, line 64
def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: JITTER_DEFAULT, report: false)
rescue_from(*exceptions) do |error|
executions = executions_for(exceptions)
if attempts == :unlimited || executions < attempts
ActiveSupport.error_reporter.report(error, source: "application.active_job") if report
retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions, jitter: jitter), queue: queue, priority: priority, error: error
else
if block_given?
instrument :retry_stopped, error: error do
yield self, error
end
run_after_discard_procs(error)
else
instrument :retry_stopped, error: error
run_after_discard_procs(error)
raise error
end
end
end
end Перехватить исключение и запланировать повторное выполнение задачи через указанное количество секунд, ограничив число попыток. Если исключение продолжает возникать после указанного числа попыток, оно передаётся базовой системе очередей, которая может использовать собственный механизм повторных попыток или поместить задачу в очередь ожидания для проверки.
Можно также передать блок, который будет вызван, если попытки повторного выполнения не увенчаются успехом. Это позволяет реализовать собственную логику вместо передачи исключения дальше. Блоку передаются экземпляр задачи в качестве первого параметра и экземпляр ошибки в качестве второго.
Обработчики retry_on и discard_on ищутся снизу вверх, а затем вверх по иерархии классов. Если таковой имеется, вызывается обработчик первого класса, для которого выполняется условие exception.is_a?(klass).
Параметры
-
:wait— повторно ставит задачу в очередь с задержкой, заданной в секундах (по умолчанию: 3 секунды), вычисляемым proc, принимающим в качестве аргумента количество уже выполненных запусков, или ссылкой на символ:polynomially_longer, которая применяет алгоритм ожидания((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2(сначала около 3 с, затем около 18 с, потом около 83 с и т. д.) -
:attempts— ставит задачу в очередь указанное число раз (по умолчанию: 5 попыток) или использует ссылку на символ:unlimited, чтобы повторять попытки, пока задача не завершится успешно. В число попыток входит первоначальный запуск задачи. -
:queue— повторно ставит задачу в другую очередь -
:priority— повторно ставит задачу в очередь с другим приоритетом -
:jitter— случайная задержка, добавляемая ко времени ожидания при расчёте интервала между попытками. По умолчанию составляет 15% (0.15) — это верхняя граница возможного времени ожидания (выраженная в процентах) -
:report— ошибки перед повторной попыткой передаются системе отчётовRails.error
Примеры
class RemoteServiceJob < ActiveJob::Base
retry_on CustomAppException # defaults to ~3s wait, 5 attempts
retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 }
retry_on CustomInfrastructureException, wait: 5.minutes, attempts: :unlimited
retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
retry_on Net::OpenTimeout, Timeout::Error, wait: :polynomially_longer, attempts: 10 # retries at most 10 times for Net::OpenTimeout and Timeout::Error combined
# To retry at most 10 times for each individual exception:
# retry_on Net::OpenTimeout, wait: :polynomially_longer, attempts: 10
# retry_on Net::ReadTimeout, wait: 5.seconds, jitter: 0.30, attempts: 10
# retry_on Timeout::Error, wait: :polynomially_longer, attempts: 10
retry_on YetAnotherCustomAppException, report: true
retry_on EvenWorseCustomAppException do |job, error|
CustomErrorHandlingCode.handle(job, error)
end
def perform(*args)
# Might raise CustomAppException, AnotherCustomAppException, or YetAnotherCustomAppException for something domain specific
# Might raise ActiveRecord::Deadlocked when a local db deadlock is detected
# Might raise Net::OpenTimeout or Timeout::Error when the remote service is down
end
end
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.