如何标记sidekiq任务/作业重试而不引发错误?

时间:2016-02-29 23:20:51

标签: ruby-on-rails sidekiq

我使用Sidekiq队列来处理与不可靠的第三方API的通信。由于这个API通常会一次停机几分钟然后再次备份,所以Sidekiq非常方便。当发生连接问题时,会引发错误,并且Sidekiq会在一段时间过后将作业重新放回队列中以便稍后再次重试。

我使用NewRelic不仅可以帮助调试崩溃,还可以用于监控。我的问题是上面这个当前的方法在NewRelic中创建了错误。如果第三方API停机超过几分钟,则错误计数会累积到足以导致通过NewRelic发送通知。

我想做的只是在工作发生一定次数的重试时,从我的工作人员那里提出错误。我正在使用sidekiq_retries_exhausted来执行此操作。我的问题是,我不太确定如何在没有引发错误的情况下将作业放回队列中。

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

3 个答案:

答案 0 :(得分:3)

您引发特定错误并告诉错误服务忽略该类型的错误。对于NewRelic:

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

答案 1 :(得分: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]

在特定作业 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 :(得分:0)

以下是我为AirBrake保留故意重试错误所做的工作:

+ curl https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py -O
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
^M  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0^M100 56093  100 56093    0     0  56093      0  0:00:01 --:--:--  0:00:01 98929
+ chmod +x ./awslogs-agent-setup.py
+ ./awslogs-agent-setup.py -n -c /etc/awslogs/awslogs.conf -r us-west-2

Step 1 of 5: Installing pip ...^[[0mlibyaml-dev does not exist in system ^[[0m^[[92mDONE^[[0m

Step 2 of 5: Downloading the latest CloudWatch Logs agent bits ... ^[[0mTraceback (most recent call last):
  File "./awslogs-agent-setup.py", line 1317, in <module>
    main()
  File "./awslogs-agent-setup.py", line 1313, in main
    setup.setup_artifacts()
  File "./awslogs-agent-setup.py", line 858, in setup_artifacts
    self.install_awslogs_cli()
  File "./awslogs-agent-setup.py", line 570, in install_awslogs_cli
    subprocess.call([AWSCLI_CMD, 'configure', 'set', 'plugins.cwlogs', 'cwlogs'], env=DEFAULT_ENV)
  File "/usr/lib/python2.7/subprocess.py", line 168, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 390, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1025, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

告诉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

最好使你的异常名称显然不是一个错误(例如RetryLaterNotAnError),因为它仍然会出现在日志中等等,并且当你看到很多人时你不想让人们知道。

PS。也就是说,我真的喜欢看Sidekiq提供一个明确的,无错误的重试机制。