【问题标题】:How to mark a sidekiq task/job for retry without raising an error?如何在不引发错误的情况下将 sidekiq 任务/作业标记为重试?
【发布时间】:2016-06-13 05:04:11
【问题描述】:

我使用 Sidekiq 队列来处理与不可靠的第 3 方 API 的通信。由于此 API 经常一次关闭几分钟,然后再次备份,Sidekiq 很方便。当发生连接问题时,会引发错误,Sidekiq 会将作业扔回队列中,以便稍后在一段时间后重试。

我使用 NewRelic 不仅可以帮助调试崩溃,还可以用于监控。我的问题是,上面的这种当前方法会在 NewRelic 中产生错误。如果 3rd 方 API 关闭超过几分钟,错误计数会累积到足以导致通知通过 NewRelic 发送出去。

我想做的只是在工作重试达到一定次数时从我的工作人员那里引发错误。我正在使用sidekiq_retries_exhausted 来执行此操作。我的问题是我不太确定如何在作业出现错误后将它们放回队列而不引发错误。

Sidekiq 是否提供任何工具来将作业返回到队列、增加作业的重试次数,并让它一直待在那里直到它再次运行,就好像在工人类中引发了异常一样?

【问题讨论】:

    标签: ruby-on-rails sidekiq


    【解决方案1】:

    如果使用 Sidekiq Enterprise,另一种选择可能是使用可选的附加错误类型集,这些错误类型将被视为 Sidekiq::Limiter::OverLimit 违规。

    出于我的目的,我使用了一个新的错误类,然后将其添加到配置中的列表中。以下是 sidekiq-ent 代码(不在公共 sidekiq 存储库中)关于如何修改配置文件的注释:

        # An optional set of additional error types which would be
        # treated as a rate limit violation, so the job would automatically
        # be rescheduled as with Sidekiq::Limiter::OverLimit.
        #
        # Sidekiq::Limiter.errors << MyApp::TooMuch
        # Sidekiq::Limiter.errors = [Foo::Error, MyApp::Limited]
    

    具体job里面you can specify the max_retries,否则默认为20:

    sidekiq_options max_limiter_retries: 10
    

    在工作中,我将挽救我不想完全忽略的“预期”间歇性错误,然后引发我添加到列表中的错误,如下所示:

    rescue RestClient::RequestTimeout => e
      raise SidekiqSoftRetry.new(e.inspect)
    end
    

    这是我的初始化文件中的内容 - Mike Perham 是 kind enough to respond,可以选择更新全局重试限制。

    class SidekiqSoftRetry < RuntimeError
    end
    Sidekiq::Limiter::DEFAULT_OPTIONS[:reschedule] = 10
    Sidekiq::Limiter.configure do |config|
      config.errors.concat(
        [   
          SidekiqSoftRetry,
        ]
      )
    end
    

    【讨论】:

      【解决方案2】:

      为了避免 AirBrake 出现故意重试错误,我采取了以下措施:

      class TaskWorker
        include Sidekiq::Worker
      
        class RetryNotAnError < RuntimeError
        end
      
        def perform task_id
          task = Task.find(task_id)
          task.do_cool_stuff
      
          if task.finished?
            @log.debug "Task #{task_id} was successful."
            return false
          else
            @log.debug "Task #{task_id} will try again later."
            raise RetryNotAnError, task_id
          end
        end
      end
      

      告诉 Airbrake 忽略它:

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

      最好让您的异常名称明显不是错误(例如 RetryLaterNotAnError),因为它仍会显示在日志等中,而且您不想在人们看到一堆异常时吓坏他们。

      ps。也就是说,我真的希望看到 Sidekiq 提供一个明确的、无错误的重试机制。

      【讨论】:

        【解决方案3】:

        您提出一个特定错误并告诉错误服务忽略该类型的错误。对于NewRelic:

        https://docs.newrelic.com/docs/agents/ruby-agent/installation-configuration/ruby-agent-configuration#error_collector.ignore_errors

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-03
          • 1970-01-01
          • 2011-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-30
          • 1970-01-01
          相关资源
          最近更新 更多