ruby 将重试的sidekiq作业放在队列的开头

4szc88ey  于 2023-08-04  发布在  Ruby
关注(0)|答案(2)|浏览(120)

我有sidekiq队列与~100000工作。有些作业失败了,这没关系,因为它们通常在被sidekiq重试时成功。
然而,来自RetrySet的那些作业被添加到我们队列的末尾。很长一段时间过去,直到作业再次处理。
如何将重试的作业放在队列的开头,以便优先处理它们?

bttbmeg0

bttbmeg01#

我不相信有一个很好的答案,因为如果我记得正确的Sidekiq队列使用Redis列表,所以有一个FIFO的期望。重试的作业将在同一队列中排队,因此这意味着它们将始终位于最后。
一种方法不是很好,也不是我推荐的方法,是添加另一个队列,并将作业重试发送到它:

# config/sidekiq.yml
---
:queues:
  - default
  - my_worker_retries

字符串
将工作进程设置为不重试:

class MyWorker
  include Sidekiq::Worker
  sidekiq_options retry: false
end


确保worker可预见地引发错误,如下所示:

class MyWorker
  include Sidekiq::Worker
  sidekiq_options retry: false

  def perform(arg)
    raise ArgumentError
  end
end


添加一些逻辑来处理该异常,然后通过新创建的队列再次运行此作业:

class MyWorker
  include Sidekiq::Worker
  sidekiq_options retry: false

  def perform(arg)
    begin
      raise ArgumentError
    rescue ArgumentError => error
      MyWorker.set(queue: :my_worker_retries).perform_async(arg)
    end
  end
end


这意味着任何失败并在my_worker_retries队列中排队的作业都可能陷入无限循环-作业失败,被救出,排队,再次失败-更糟糕的是,由于您没有使用Sidekiq内置的重试排队机制,因此没有回退算法来确保重试不会像CPU可以处理的那样快。
整个东西都很脆弱。
您可以尝试通过传递一个参数来防止这种情况,该参数指示此作业已重试的次数,以便您可以在某个数字后停止:

class MyWorker
  include Sidekiq::Worker
  sidekiq_options retry: false

  MAX_RETRIES = 5

  def perform(arg, retries = 0)
    raise 'Too many retries' if retries >= MAX_RETRIES

    begin
      raise ArgumentError
    rescue ArgumentError => error
      MyWorker.set(queue: :my_worker_retries).perform_async(arg, retries + 1)
    end
  end
end


你可以扩展它来拥有一个你自己的回退算法:

MyWorker.set(queue: :my_worker_retries).perform_in((retries + 1).hours, arg, retries + 1)


所有这些都不是理想的,但它确实回答了这个问题。我当然希望有比这更好的解决方案。
有一些Sidekiq扩展可能会工作,例如https://github.com/chartmogul/sidekiq-priority_queue,但我以前没有使用过它们。

t1qtbnec

t1qtbnec2#

如果您希望失败的作业在重试时位于队列的 * 开头 *,那么这意味着重试之间的等待时间为0
在这种情况下,您应该简单地将作业执行代码的主要部分 Package 在begin/rescue块中,然后立即重试。
请注意,您还需要一个“退出”,例如。重试固定次数或特定时间间隔,否则中毒消息将导致您的工作进程无限期地处理同一消息(就像其他消息代理将拒绝的消息返回到队列顶部一样,例如RabbitMQ)

相关问题