Rails:取消Sidekiq的预定作业

时间:2014-06-12 09:27:17

标签: ruby-on-rails sidekiq

所以我的模型中有一个Sidekiq工作人员,看起来像这样:

class Perk < ActiveRecord::Base

include Sidekiq::Worker
include Sidekiq::Status::Worker

after_save :update_release_time

def update_release_time
  if self.release_time_changed?
    #if scheduled job already exists then cancel and reschedule
    #  Sidekiq::Status.cancel scheduled_job_id
    #  scheduled_job_id = NotifierWorker.perform_at(time.seconds.from_now, .....)
    #elsif scheduled job doesn't exist, then schedule for the first time
    #  scheduled_job_id = NotifierWorker.perform_at(time.seconds.from_now, .....)
    #end
  end
end
end

基本上,我的代码检查发布时间是否已经改变。如果有,则必须取消先前安排的作业并在新的时间安排它。我如何实现这一点,即代替我的伪代码?如何检查scheduled_job_id是否存在然后获取其ID?

3 个答案:

答案 0 :(得分:20)

API文档概述了您可以执行的操作,但您确实需要深入了解源代码以发现所有功能。

你可以这样做,但效率不高。这是JID找到预定作业的线性扫描。

require 'sidekiq/api'
Sidekiq::ScheduledSet.new.find_job(jid).try(:delete)

或者,您的工作可以查看它在运行时是否仍然相关。

答案 1 :(得分:1)

您编写的伪代码应该可以工作,但我会删除if / else块。如果找不到该项,Sidekiq::Status.cancel将返回false。所以下面的伪代码应该没问题:

1)Cancel scheduled_job_id if scheduled_job_id.present?

2)运行NotifierWorker.perform_at ... - 无论你是否取消,都会这样做。

但是,我会注意到,正如@ mike-perham所说,它会很慢(线性搜索)。因此,当我实现Sidekiq::Status.cancel时,我为时间戳添加了可选的第二个参数。如果您传递时间戳,那么Redis将使用二进制搜索找到与该时间匹配的计划任务,因此它只需要在同一时间安排的项目之间进行线性搜索。

因此,取消时你应该运行:

Sidekiq::Status.cancel(self.scheduled_job_id, self.release_time_was)

答案 2 :(得分:1)

使用保存在数据库或缓存中的UUID来确保您仍然需要运行作业。

class SmartWorker
  include Sidekiq::Worker
  sidekiq_options :queue => :low,
                  :retry => false,
                  :backtrace => false

  def self.schedule id
    uuid = SecureRandom.uuid
    Redis.new.set("#{id}-key", uuid)
    SmartWorker.perform_in(1.minute, id, uuid)
  end

  def perform(id, uuid, force=false)
    return unless uuid == Redis.new.get("#{id}-key")
    if force || CronLockService.lock("lock", 5000)
      begin
        Model.find(id).relation.find_each{|it|
          Service.do_it(it)
        }
      ensure
        CronLockService.expire("lock")
      end
    end
  end
end

所以,如果发生这种情况,它只会运行一次

SmartWorker.schedule 1    
SmartWorker.schedule 1