如何让ExceptionNotifier在Rails 3中与delayed_job一起使用?

时间:2021-01-18 00:03:03

I'd like ExceptionNotifier to send out an email when an exception happens in a delayed job, just like for other exceptions. How can I achieve that?

我希望ExceptionNotifier在延迟作业中发生异常时发送电子邮件,就像其他异常一样。我怎样才能做到这一点?

6 个解决方案

#1


23  

I do this with Rails 3.2.6, delayed_job 3.0.3 and exception_notification 2.6.1 gem

我使用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'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

It's probably a good idea to load this code in all environments to catch errors after bundle update etc before they reach production. I do this by having a config/initializers/delayed_job.rb file but you could duplicate the code for each config/environments/* environment.

在所有环境中加载此代码以在捆绑更新之后捕获错误(在它们到达生产之前)可能是个好主意。我通过使用config / initializers / delayed_job.rb文件来完成此操作,但您可以复制每个config / environments / *环境的代码。

Another tip is to tune the delayed job config a bit as default you may get a lot of duplicate exception mails when job fails.

另一个提示是将延迟的作业配置调整为默认值,当作业失败时,您可能会收到大量重复的异常邮件。

# In config/initializers/delayed_job_config.rb
Delayed::Worker.max_attempts = 3

Update I had some problems with the delayed_job daemon silently exiting and it turned out to be when ExceptionNotifier fails to send mail and no one rescued the exception. Now the code rescues and log them.

更新我有一些问题,remote_job守护进程默默地退出,结果是ExceptionNotifier无法发送邮件,没有人救出该异常。现在代码拯救并记录它们。

#2


4  

Adding to @MattiasWadman answer, since exception_notification 4.0 there's a new way to handle manual notify. So instead of:

添加到@MattiasWadman答案,因为exception_notification 4.0有一种处理手动通知的新方法。所以代替:

ExceptionNotifier::Notifier.background_exception_notification(error)

use

使用

ExceptionNotifier.notify_exception(error)

#3


3  

Another way to handle exceptions (put as an initializer):

另一种处理异常的方法(作为初始化器):

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


2  

For exception_notification 3.0.0 change:

对于exception_notification 3.0.0更改:

ExceptionNotifier::Notifier.background_exception_notification(error)

to:

至:

ExceptionNotifier::Notifier.background_exception_notification(error).deliver

#5


0  

simpler and updated answer:

更简单和更新的答案:

# 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

And test on console with:

并在控制台上测试:

Delayed::Job.enqueue (JS=Struct.new(:a){ def perform; raise 'here'; end }).new(1)

#6


0  

alias_method_chain no longer exists in Rails 5.

raails 5中不再存在alias_method_chain。

Here's the new (proper) way to do this using Ruby 2's prepend

这是使用Ruby 2的前置实现此功能的新(正确)方法

# 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

#1


23  

I do this with Rails 3.2.6, delayed_job 3.0.3 and exception_notification 2.6.1 gem

我使用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'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

It's probably a good idea to load this code in all environments to catch errors after bundle update etc before they reach production. I do this by having a config/initializers/delayed_job.rb file but you could duplicate the code for each config/environments/* environment.

在所有环境中加载此代码以在捆绑更新之后捕获错误(在它们到达生产之前)可能是个好主意。我通过使用config / initializers / delayed_job.rb文件来完成此操作,但您可以复制每个config / environments / *环境的代码。

Another tip is to tune the delayed job config a bit as default you may get a lot of duplicate exception mails when job fails.

另一个提示是将延迟的作业配置调整为默认值,当作业失败时,您可能会收到大量重复的异常邮件。

# In config/initializers/delayed_job_config.rb
Delayed::Worker.max_attempts = 3

Update I had some problems with the delayed_job daemon silently exiting and it turned out to be when ExceptionNotifier fails to send mail and no one rescued the exception. Now the code rescues and log them.

更新我有一些问题,remote_job守护进程默默地退出,结果是ExceptionNotifier无法发送邮件,没有人救出该异常。现在代码拯救并记录它们。

#2


4  

Adding to @MattiasWadman answer, since exception_notification 4.0 there's a new way to handle manual notify. So instead of:

添加到@MattiasWadman答案,因为exception_notification 4.0有一种处理手动通知的新方法。所以代替:

ExceptionNotifier::Notifier.background_exception_notification(error)

use

使用

ExceptionNotifier.notify_exception(error)

#3


3  

Another way to handle exceptions (put as an initializer):

另一种处理异常的方法(作为初始化器):

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


2  

For exception_notification 3.0.0 change:

对于exception_notification 3.0.0更改:

ExceptionNotifier::Notifier.background_exception_notification(error)

to:

至:

ExceptionNotifier::Notifier.background_exception_notification(error).deliver

#5


0  

simpler and updated answer:

更简单和更新的答案:

# 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

And test on console with:

并在控制台上测试:

Delayed::Job.enqueue (JS=Struct.new(:a){ def perform; raise 'here'; end }).new(1)

#6


0  

alias_method_chain no longer exists in Rails 5.

raails 5中不再存在alias_method_chain。

Here's the new (proper) way to do this using Ruby 2's prepend

这是使用Ruby 2的前置实现此功能的新(正确)方法

# 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