Я бы хотел, чтобы ExceptionNotifier отправил электронное письмо, когда исключение происходит в задании с задержкой, как и для других исключений. Как я могу это достичь?
Как заставить ExceptionNotifier работать с delayed_job в Rails 3?
Ответ 1
Я делаю это с Rails 3.2.6, delayed_job 3.0.3 и exception_notification 2.6.1 gem
# In config/environments/production.rb or config/initializers/delayed_job.rb
# Optional but recommended for less future surprises.
# Fail at startup if method does not exist instead of later in a background job
[[ExceptionNotifier::Notifier, :background_exception_notification]].each do |object, method_name|
raise NoMethodError, "undefined method `#{method_name}' for #{object.inspect}" unless object.respond_to?(method_name, true)
end
# Chain delayed job handle_failed_job method to do exception notification
Delayed::Worker.class_eval do
def handle_failed_job_with_notification(job, error)
handle_failed_job_without_notification(job, error)
# only actually send mail in production
if Rails.env.production?
# rescue if ExceptionNotifier fails for some reason
begin
ExceptionNotifier::Notifier.background_exception_notification(error)
rescue Exception => e
Rails.logger.error "ExceptionNotifier failed: #{e.class.name}: #{e.message}"
e.backtrace.each do |f|
Rails.logger.error " #{f}"
end
Rails.logger.flush
end
end
end
alias_method_chain :handle_failed_job, :notification
end
Вероятно, неплохо загрузить этот код во всех средах, чтобы поймать ошибки после обновления пакета и т.д., прежде чем они достигнут производства. Я делаю это, имея файл config/initializers/delayed_job.rb
, но вы можете дублировать код для каждой среды config/environments/*
.
Еще один совет - немного настроить конфигурацию с задержкой заданий по умолчанию, при неудачном выполнении задания вы можете получить много дубликатов исключений.
# In config/initializers/delayed_job_config.rb
Delayed::Worker.max_attempts = 3
Обновление. У меня возникли проблемы с демонтажем delayed_job
, и он оказался, когда ExceptionNotifier
не удалось отправить почту, и никто не спас это исключение. Теперь код спасет и зарегистрирует их.
Ответ 2
Добавление в @MattiasWadman ответа, так как exception_notification 4.0 есть новый способ обработки уведомлений вручную. Поэтому вместо:
ExceptionNotifier::Notifier.background_exception_notification(error)
использование
ExceptionNotifier.notify_exception(error)
Ответ 3
Другой способ обработки исключений (поместить в качестве инициализатора):
class DelayedErrorHandler < Delayed::Plugin
callbacks do |lifecycle|
lifecycle.around(:invoke_job) do |job, *args, &block|
begin
block.call(job, *args)
rescue Exception => e
# ...Process exception here...
raise e
end
end
end
end
Delayed::Worker.plugins << DelayedErrorHandler
Ответ 4
Для исключения exception_notification 3.0.0:
ExceptionNotifier::Notifier.background_exception_notification(error)
в
ExceptionNotifier::Notifier.background_exception_notification(error).deliver
Ответ 5
более простой и обновленный ответ:
# Chain delayed job handle_failed_job method to do exception notification
Delayed::Worker.class_eval do
def handle_failed_job_with_notification job, error
handle_failed_job_without_notification job, error
ExceptionNotifier.notify_exception error,
data: {job: job, handler: job.handler} rescue nil
end
alias_method_chain :handle_failed_job, :notification
end
И протестируйте консоль с помощью:
Delayed::Job.enqueue (JS=Struct.new(:a){ def perform; raise 'here'; end }).new(1)