Как заставить ExceptionNotifier работать с delayed_job в Rails 3? - PullRequest
25 голосов
/ 12 мая 2011

Я бы хотел, чтобы ExceptionNotifier отправлял электронное письмо, когда исключение возникает в отложенной работе, как и для других исключений.Как я могу этого достичь?

Ответы [ 6 ]

23 голосов
/ 06 августа 2011

Я делаю это с Rails 3.2.6, delayed_job 3.0.3 и уведомлением об исключении 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's 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 не удалось отправить почту и никто не спас исключение. Теперь код спасает и регистрирует их.

5 голосов
/ 09 декабря 2013

Добавление к ответу @MattiasWadman, поскольку в уведомлении об исключении 4.0 появился новый способ обработки ручного уведомления . Так что вместо:

ExceptionNotifier::Notifier.background_exception_notification(error)

использование

ExceptionNotifier.notify_exception(error)
3 голосов
/ 25 августа 2015

Другой способ обработки исключений (в качестве инициализатора):

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
2 голосов
/ 15 мая 2018

alias_method_chain больше не существует в Rails 5.

Вот новый (правильный) способ сделать это, используя Ruby 2's prepend

# In config/initializers/delayed_job.rb
module CustomFailedJob
  def handle_failed_job(job, error)
    super
    ExceptionNotifier.notify_exception(error, data: {job: job})
  end
end

class Delayed::Worker
  prepend CustomFailedJob
end
2 голосов
/ 08 января 2013

Для уведомления об исключении 3.0.0 изменение:

ExceptionNotifier::Notifier.background_exception_notification(error)

до:

ExceptionNotifier::Notifier.background_exception_notification(error).deliver
0 голосов
/ 13 августа 2013

более простой и обновленный ответ:

# Chain delayed job's 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)
...