如何使Delayed_Job在ActionMailer遇到错误时通知Airbrake?

12
文档提到了钩子,包括一个错误钩子,但仅在自定义子类的上下文中提及。

这个相似的问题(没有答案)说将同样的钩子添加到类中没有起作用。

有什么诀窍吗?

更新:

总的来说,我想知道如何添加钩子以触发使用object.delay.action()语法的,在这里我看不到明显的链接到一个<____Job>类。


1
这里提供更新且更简单的答案:https://dev59.com/_mgt5IYBdhLWcg3w2RCU#17029430 - Subhas
4个回答

20

我也在寻找解决这个问题的方法,并发现了这个代码片段

我不知道它来自哪里(在Google上找到的),但是它似乎很好地完成了工作,非常简单,并且似乎遵循了DelayedJob的插件系统,这是我甚至没有意识到的...

这是一个稍微改进的版本,使用了先前的猴子补丁代码的部分:

# https://gist.github.com/2223758
# modified

module Delayed
  module Plugins
    class Airbrake < Plugin
      module Notify
        def error(job, error)
          ::Airbrake.notify_or_ignore(
            :error_class   => error.class.name,
            :error_message => "#{error.class.name}: #{error.message}",
            :parameters    => {
              :failed_job => job.inspect,
            }
          )
          super if defined?(super)
        end
      end

      callbacks do |lifecycle|
        lifecycle.before(:invoke_job) do |job|
          payload = job.payload_object
          payload = payload.object if payload.is_a? Delayed::PerformableMethod
          payload.extend Notify
        end
      end
    end
  end
end

Delayed::Worker.plugins << Delayed::Plugins::Airbrake
它将添加错误信息和有效负载,以便在Airbrake中可用。

我之前不知道这个插件系统。我会去看一下。如果它在我的系统中可行,我很快就会把采纳答案改成你的。 - Jordan Feldstein
9
我非常喜欢这种方法。我找不到发布为 gem 版本的版本,所以为了感谢您的分享,我将它打包成一个 gem,以便其他人可以轻松使用。如果您想要写入权限等,请让我知道!https://github.com/benjaminoakes/delayed-plugins-airbrake - Benjamin Oakes
这是最佳答案,因为它适用于所有工作,它不是猴子补丁,并且您不必记得在添加delay的新用法时添加钩子。此外,我会使用@benjamin-oakes的gem,除非我正在使用party_foul而不是airbrake。 - monozok

2

谢谢,问题是关于Airbrake的,但这个回答类似且不错。(现在也有一个Airbrake gem)。https://github.com/benjaminoakes/delayed-plugins-airbrake - Jordan Feldstein
1
你说得对,@JordanFeldstein,这个问题是关于Airbrake的。有趣的是,我也用了同样的方法来处理honeybadger,而且效果非常好。我猜Airbrake和Honeybadger的API响应相同的调用(这是非常好的事情)。 - lsaffie
此插件已经不再适用于最新版本的Honeybadger。 - user1724295

1

最好的方法是使用全局钩子。有人在2011年提出了这个想法,但似乎还没有被实现。

与此同时,可以尝试用猴子补丁来解决问题:

# Patch delayed job to report runtime errors to Airbrake
module Delayed
  class Worker

    protected

    def handle_failed_job_with_airbrake(job, error)
      ::Airbrake.notify(
        :error_class   => error.class.name,
        :error_message => "#{error.class.name}: #{error.message}",
        :parameters    => {
          :failed_job => job.inspect,
        }
      )

      handle_failed_job_without_airbrake(job, error)
    end

    alias_method_chain :handle_failed_job, :airbrake

  end
end

1
由于Airbrake显示参数的方式,我建议不要发送job.inspect,而是传递一个哈希。首先解析失败作业的内容:failed_job = YAML.load(job.handler)。然后将其实例参数解析为哈希,您可以将其传递给Airbrake的:parametersfailed_job.instance_variables.inject({}) { |hsh,v| hsh[v.to_s.gsub(/[^\w]/, '')] = failed_job.instance_variable_get(v); hsh } - iainbeeston
1
你可能还想在 :parameters 中包含作业的类名::class => failed_job.class.name - iainbeeston

1

让delayed_job在作业失败时发送警报到Airbrake的最简单方法可能是对其进行monkey-patch。这允许您钩入delayed_job的内部,并稍微修改它以在出现问题时向Airbrake发出警报。

不幸的是,如何做到这一点将取决于您使用的delayed_job版本和Airbrake版本;也可能取决于您想要在delayed_job处理过程中的哪个位置钩入系统。

然而,我看到的实现你想要的功能的最简单的例子可能是对handle_failed_job方法进行monkey-patch,如此处所示。请注意,此示例使用旧的Hoptoad系统进行警报,因此,如果您使用现代的Airbrake gem,则需要更改实际通知的代码,如此处所述。


谢谢你提醒我。最终我也找到了相同的猴子补丁解决方案。代码片段如上所示。 - Jordan Feldstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接