Error reporting when sending emails with delayed_job

对着背影说爱祢 提交于 2019-12-04 03:23:39

Updated Solution

Overall the solution is quite simple. If you have are doing delayed_job on an Object (like MyClass.new.delay.some_method), then you need to define error handling as an object method. If you're doing delayed_job on a Class (like MyTestMailer.test_email ...), then you need to define error handling as a class method.

Let's say you have a mailer called TestMailer. The solution is to define the error handling as a class method, not an object method:

# Your rails mailer
class TestMailer

  # Whoa! error has to be a class method!
  def self.error(job, e)
    puts "I can now handle test mailer errors in delayed job!!!!"
  end

end

Now the above def self.error method will be used as the error callback in the delayed job!

Or if you want to be able to handle all action mailer errors,

class ActionMailer::Base
  def self.error(job, e)
    puts "I can now handle all mailer errors in delayed job!!!"
  end
end

The reason is because of the way DelayedJob's internal PerformableMethod handles errors. A PerformableMethod has two things: a Target Object, and a Target Method. In Action Mailer's case, the Target Object is not an object, but your mailer class TestMailer. The target method is the mail method that you use, say test_mail. DelayedJob looks for all the hooks (error, before, after, etc) on the Target Object. But in our case, the Target Object is the class itself. Hence the hooks have to be defined as class methods.

The way DelayedJob handles ActionMailer mails is a little hacky. If you add an object method instead of a class method, it throws an unwanted exception. For example, here is the code:

# In <delayed-job-gem>/lib/delayed/performable_method.rb
module Delayed
  class PerformableMethod

    # line #7
    delegate :method, :to => :object

Every object in ruby has a method function, which is used to get a raw reference to a method inside that class. But in DelayedJob - this raw method function has been kind of delegated to some other target object. This hack prevents us from normally using the def error function for handling job errors.

Edit: Added footnote, minor clarification

Edit 2: Reordered answer

Roman

First, a module for inclusion in mailer and, possibly, other delayed jobs:

module Delayed
  module Airbrake
    # Send error via Airbrake
    def error(job, e)
      ::Airbrake.notify(e, :component => job.name, :action => 'perform', :parameters => {:job => job.inspect})
    end
 end

end

then include it:

Delayed::PerformableMailer.send(:include, Delayed::Airbrake)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!