【问题标题】:Sidekiq/Airbrake only post exception when retries extinguishedSidekiq/Airbrake 仅在重试消失时发布异常
【发布时间】:2013-10-30 12:43:31
【问题描述】:

我希望 Airbrake 仅在重试用尽时才收到错误通知,但我似乎想不出实现它的方法...

我可以添加一个 sidekiq_retries_exhausted 钩子来将错误发送到 AirBrake,但我能想到捕捉实际失败的唯一方法是添加一个吞下错误的中间件,但是如果存在,该作业将被标记为成功没有错误...那么永远不会有任何重试..

希望这是有道理的!

【问题讨论】:

  • 您可以挽救并提出您自己的作业错误异常(管理您认为合适的原始错误),然后将该自定义作业错误异常添加到 aibrake 忽略列表中。如果我误解了您的问题,我们深表歉意。
  • 你理解正确,但我宁愿错误根本没有出现在 Airbrake...
  • 澄清一下,我的意思是,你将perform 代码包装在一个开始/救援块中,然后记录出现的任何可能导致重试的错误,而是引发一个通用的WorkerPerformError 之类的异常并将其添加到您忽略的异常列表中。这样,原始异常被抑制,自定义异常触发重试。我将不得不在我最近继承的一个项目中实现类似的东西,所以当我有的时候我会发布一个更深思熟虑的解决方案。
  • 刚刚找到这个可能有帮助的帖子:librelist.com/browser//sidekiq/2012/12/8/…

标签: ruby-on-rails ruby-on-rails-4 sidekiq airbrake


【解决方案1】:

我设法使用插入列表开头的 Sidekiq 中间件来实现这一点:

class RaiseOnRetriesExtinguishedMiddleware
    include Sidekiq::Util

  def call(worker, msg, queue)
    yield
  rescue Exception => e
    bubble_exception(msg, e)
  end

  private

  def bubble_exception(msg, e)
    max_retries = msg['retries'] || Sidekiq::Middleware::Server::RetryJobs::DEFAULT_MAX_RETRY_ATTEMPTS
    retry_count = msg['retry_count'] || 0
    last_try = !msg['retry'] || retry_count == max_retries - 1

    raise e if last_try
  end

  def retry_middleware
    @retry_middleware ||= Sidekiq::Middleware::Server::RetryJobs.new
  end
end

如果它是最后一次尝试并抛出异常,它会让它冒泡(到 Airbrake),否则它不会。这不会影响失败记录,因为这会发生在链的后面。

【讨论】:

    【解决方案2】:

    如图here(不是我的代码):

        Airbrake.configure do |config|
          config.api_key = '...'
          config.ignore_by_filter do |exception_data|
            exception_data[:parameters] && 
            exception_data[:parameters]['retry_count'].to_i > 0
          end
        end
    

    【讨论】:

    • 这是一种方法,虽然我认为我的解决方案更干净,但谢谢
    • 这一行是多余的:exception_data[:parameters]['retry_count'] &&
    • 就是这样。已删除。
    【解决方案3】:

    我遇到了完全相同的事情,并希望将其排除在 AirBrake 之外。这是我所做的,易于阅读且简单:

    class TaskWorker
      include Sidekiq::Worker
    
      class RetryLaterNotAnError < RuntimeError
      end
    
      def perform task_id
        task = Task.find(task_id)
        task.do_cool_stuff
    
        if task.finished?
          @log.debug "Nothing to do for task #{task_id}"
          return false
        else
          raise RetryLaterNotAnError, task_id
        end
      end
    end
    

    然后,让 Airbrake 忽略它:

    Airbrake.configure do |config|
      config.ignore << 'RetryLaterNotAnError'
    end
    

    瞧!

    【讨论】:

    • 不要这样做。这很糟糕,而且不是正确的解决方案。
    • 我发现它很好地满足了我的需求,但我总是渴望学习。这有什么可怕的?什么是更合适的解决方案?
    • Sidekiq 公开了一个“retries_exhausted”块,它允许您在之后不再重试时处理最后一次失败的最后一个异常。我们应该使用它。任何时候你对控制流使用异常,你都应该重新评估。您将引发异常作为解决方法,而不是正确支持逻辑。 Sidekiq 有知道什么时候不重试的逻辑,因此,当 sidekiq 选择不重试时,我们应该能够挂钩到 sidekiq 做事情。
    • 此解决方法不是实现 retries_exhausted 功能。相反,这允许我的 TaskWorker 向 sidekiq 发出信号以便稍后重试(使用它带来的所有退避/到期糖果),而不会因为毫无意义的异常而使我的 Airbrake 日志混乱。真正的驱动因素是,向 sidekiq 发出稍后重试的唯一方法是引发异常。这并不理想(IMO),为此有一个功能请求github.com/mperham/sidekiq/issues/1704#issuecomment-390795666
    【解决方案4】:

    这是我们为 Bugsnag 做的事情,您可以为 Airbrake 进行自定义。

    # config/initializers/00_core_ext.rb
    class StandardError
      def skip_bugsnag?
        !!@skip_bugsnag
      end
    
      def skip_bugsnag!
        @skip_bugsnag = true
        return self
      end
    end
    
    # config/initializers/bugsnag.rb
    
      config.ignore_classes << lambda { |e| e.respond_to?(:skip_bugsnag?) && e.skip_bugsnag? }
    
    # In Sidekiq Jobs
    
    raise ErrorToRetryButNotReport.new("some message").skip_bugsnag!
    
    # Or if the error is raised by a third party
    
    begin
      # some code that calls a third-party method
    rescue ErrorToRetryButNotReport => e
      e.skip_bugsnag!
      raise
    end
    

    然后您可以手动选择从sidekiq_retries_exhausted 发送错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-03
      相关资源
      最近更新 更多