Sidekiq技术问题:delay扩展设置Job的初始位置及队列大小查询异常
Sidekiq 相关问题解答
问题1:用 delay 扩展创建的 Job 一开始存在哪里?
这个得分两种情况来看:
- 要是你用的是不带延迟的
delay方法(比如MyClass.delay.my_method),那Job会直接进Sidekiq的默认队列(一般叫default),对应Sidekiq::Queue.new("default")这个集合。 - 要是你用的是延迟调度的方法,比如
delay_for(10.seconds)或者delay_until(Time.now + 30),那Job一开始会待在Sidekiq::ScheduledSet里,等时间到了才会被移到执行队列中。
问题2:调度完Job立刻查队列/调度集大小是0,但UI里能看到Job还没执行
你碰到的这个情况其实挺常见的,我来帮你分析几个大概率的原因:
1. 搞混了不同类型Job的存储位置
如果你的代码是 MyClass.delay.my_method(无延迟),那Job应该在默认队列里,但你查的是 Sidekiq::Queue.new.size —— 这里要注意:Sidekiq::Queue.new 默认指向 default 队列,但要是你之前修改过 delay 方法的默认队列(比如通过 Sidekiq::Extensions::DelayedClass.queue = "my_queue" 改了),那得指定队列名称查询才行:
Sidekiq::Queue.new("my_queue").size
2. Job被Worker瞬间取走了
如果你的Sidekiq Worker进程在跑,而且没有其他任务积压,那刚提交的立即执行Job可能瞬间就被Worker从队列里拉走,进入“Processing”状态了。这时候队列大小自然是0,但Sidekiq UI的“Busy”页面能看到这个正在处理的Job。不过你说Job是“片刻后会执行”,那这个可能性就比较低啦。
3. 延迟调度Job的查询时机问题
要是你实际用的是延迟调度(比如 delay_for),那Job会存在 ScheduledSet 里,但Sidekiq的这个集合是基于Redis有序集合实现的,有时候刚提交的Job可能因为Redis的写入延迟,导致你立刻查询时还没被纳入集合。你可以稍微等一小会儿再查,比如:
MyClass.delay_for(5.seconds).my_method sleep 0.1 # 给Redis一点写入时间 Sidekiq::ScheduledSet.new.size # 这时候应该就能查到1了
4. 怎么检查特定类型的Job是否已调度
针对你实际场景里“渲染页面时检查特定Job是否已调度”的需求,我给你两个实用的方法:
- 首先最好给Job加个唯一标识(比如关联业务ID),这样能精准查询。
- 对于立即执行的Job,遍历对应队列的Job,检查类名和参数:
def job_scheduled?(class_name, args) Sidekiq::Queue.new("default").any? do |job| job.klass == class_name && job.args == args end end # 用的时候这么调用 job_scheduled?("MyClass", []) - 对于延迟调度的Job,遍历
ScheduledSet就行:
小提醒:如果队列里Job特别多,这种遍历方式可能会有性能问题,更靠谱的做法是调度Job时,把Job的ID存到你的业务数据库里,之后通过数据库来查状态~def delayed_job_scheduled?(class_name, args) Sidekiq::ScheduledSet.new.any? do |job| job.klass == class_name && job.args == args end end
内容的提问来源于stack exchange,提问作者Filip Kis
相关产品推荐
相关产品推荐

