You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sidekiq如何跳过重试流程直接将任务发送至Deadset

如何将任务直接发送至Sidekiq Deadset?

我检索了相关技术资料,发现不少开发者有任务失败时触发异常处理系统通知的需求,典型场景为任务需要对接可靠性不稳定的第三方API。
我的需求是直接将符合判定条件的失败任务送入Deadset,既不直接丢弃任务,也不需要等待约20天的默认重试周期结束,让运维人员可以在Deadset UI界面中根据失败原因,手动点击Retry或Delete按钮处理对应任务。

现有一个Russian Roulette示例任务:逻辑为满足幸运判定条件时任务走重试流程,不满足条件时直接进入被称为“任务墓地”的Deadset,请问该如何正确实现该逻辑?

我最初考虑在sidekiq_options中设置retry: 0,但该配置无法满足动态分支判断的需求。我曾设想通过retry方法动态传入sidekiq_options retry: 0配置,让任务下次执行时直接进入Deadset,对应示例代码如下:

class RussianRoulette < ActiveJobBase

  sidekiq_options retry: 10

  discard_on SomeException do |job, exception|
    puts "You are dead but somebody will check your corpse!"
    # How to send to deadset?
  end

  def perform(args)
    if feeling_lucky? # If this method fails it retries up to 10 times
      puts "You got another chance!"
      retry_job
    else
      puts "You are dead!"
      # What to do?:
      # throw :abort # No, because we want to send it to the deadset so somebody can erase or retry it
      # raise SomeException # Could be, but then how to send to deadset?
      # self.class.perform_later(args, {sidekiq_options: {retry: 0}}) # Is this even possible?
    end
  end
end

目前我尝试过的最接近方案是通过Sidekiq API直接向Deadset推送数据,查阅Sidekiq官方源码可知该接口要求传入message参数,我尝试将任务序列化为JSON后传入,但在WebUI中显示传入的message参数格式不正确,测试代码如下:

Sidekiq::DeadSet.new.kill(job.to_json) # Also tried job.arguments.to_json

WebUI异常显示截图

问题更新

我参考了WebUI中Kill按钮的实现逻辑,发现逻辑中会调用任务实例的kill方法,但我在控制台手动调用该方法时提示方法不存在,报错信息如下:

(byebug) job.kill
*** NoMethodError Exception: undefined method `kill' for #<RussianRoulette:0x00007faf520805a8>

正确实现方案

核心逻辑说明

Sidekiq 5.1及以上版本原生支持直接将任务送入Deadset的能力,不需要手动拼接任务参数调用底层API,也不需要额外开发中间件。
先明确之前方案的问题:

  • discard_on捕获异常后会直接删除任务,不会送入Deadset,不符合需求
  • ActiveJob封装的任务实例没有kill方法,该方法只存在于Sidekiq从Redis读取的原生任务记录对象上,直接在ActiveJob实例上调用必然报方法不存在的错误
  • 手动调用Sidekiq::DeadSet.new.kill时需要传入Sidekiq原生格式的任务载荷(包含jid、任务类、错误栈、创建时间等完整字段),直接传ActiveJob实例或参数的序列化结果会因为格式缺失无法被WebUI识别,显示异常
  • 重新入队一个retry:0的新任务会丢失原任务的执行上下文、错误栈信息,生成全新的任务ID,无法追溯原始失败记录
  • throw :abort会直接终止任务并丢弃,不会进入Deadset

可直接落地的代码

利用Sidekiq sidekiq_retry_in回调的特殊返回值:kill即可实现需求:当该回调返回:kill时,Sidekiq会跳过所有重试流程,直接将任务送入Deadset,完整保留任务上下文和错误信息,支持在WebUI手动重试或删除。

class RussianRoulette < ActiveJob::Base
  sidekiq_options retry: 10

  # 定义专门的异常标记需要直接入死信的场景,不要用discard_on捕获该异常
  class FatalGameOver < StandardError; end

  def perform(args)
    if feeling_lucky?
      puts "You got another chance!"
      # 正常重试逻辑可自定义等待时间
      retry_job wait: 1.minute
    else
      puts "You are dead! Sent to deadset for manual processing"
      # 抛出标记异常,触发直接入死信逻辑
      raise FatalGameOver, "Lost russian roulette, pending manual review"
    end
  end

  # 配置Sidekiq重试决策逻辑
  sidekiq_retry_in do |count, exception, _job_hash|
    # 碰到标记的致命异常,直接返回:kill送入Deadset
    next :kill if exception.is_a?(FatalGameOver)

    # 其他异常走正常的重试退避逻辑,最多重试10次
    (count + 1).minutes
  end
end

该方案完全匹配需求:

  • 符合判定条件的任务不会等待长重试周期,直接进入Deadset
  • 任务不会被丢弃,完整保留所有执行信息、错误栈
  • 运维可以在Deadset UI中正常操作重试或删除
  • 动态分支判断完全可控,不会影响其他异常场景的正常重试逻辑

内容的提问来源于stack exchange,提问作者damuz91

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:45:32