我希望 ExceptionNotifier 在延时任务中发生异常时能够像处理其他异常一样发送电子邮件。我该如何实现这一点?
我是用 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
在所有环境中加载此代码,以便在 bundle update 等操作后捕获错误,避免错误进入生产环境。 我通过拥有一个 config/initializers/delayed_job.rb
文件来实现此功能,但您也可以为每个 config/environments/*
环境复制该代码。
另一个提示是稍微调整延迟作业配置,因为默认情况下,当作业失败时可能会收到大量重复的异常邮件。
# In config/initializers/delayed_job_config.rb
Delayed::Worker.max_attempts = 3
更新:我遇到了一些delayed_job
守护进程默默退出的问题,原来是当ExceptionNotifier
无法发送邮件且没有人捕获异常时。现在代码进行了修复以捕获和记录异常。
delegate
的使用方式而不能通用地为“PerformableMethod”定义它。 - Nathan, :data => {:job => job}
,这样我就可以获得更多的细节信息了。 - matExceptionNotifier.notify_exception(error) if job.attempts == Delayed::Worker.max_attempts
替换原有代码:ExceptionNotifier::Notifier.background_exception_notification(error)
- micred补充@MattiasWadman的答案,自从exception_notification 4.0 有一种新的方式来处理手动通知。所以现在可以这样做:
ExceptionNotifier::Notifier.background_exception_notification(error)
ExceptionNotifier.notify_exception(error)
处理异常的另一种方式(作为初始化器):
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
alias_method_chain
在Rails 5中已经不存在。
以下是使用Ruby 2的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
Delayed::Worker.prepend CustomFailedJob
可以直接使用。 - Andres Leon针对异常通知(exception_notification)3.0.0版本的更改:
ExceptionNotifier::Notifier.background_exception_notification(error)
to:
ExceptionNotifier::Notifier.background_exception_notification(error).deliver
更简单和更新的答案:
# 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)