【问题标题】:Ruby on Rails + Sidekiq: How do I change a scheduled job start time?Ruby on Rails + Sidekiq:如何更改计划的作业开始时间?
【发布时间】:2013-04-08 13:57:34
【问题描述】:

我最近开始使用 Sidekiq,并注意到它有一个我一直在寻找的很棒的功能:

UserMailer.delay_until(5.days.from_now).find_more_friends_email

基本上我可以安排未来的工作,因此我不需要我的应用不断轮询具有开始时间的新事件。

现在这就像一个魅力,但我如何更改工作的开始时间?通常,一些预定事件的开始时间会发生变化。我如何在 sidekiq 中复制它?

我知道我可以删除作业并创建一个新作业,但是否可以只修改开始时间?

编辑:

我建立在 Oto Brglez 的想法之上,这里是文档化的代码:

module TaskStuff
  class TaskSetter
    include Sidekiq::Worker
    sidekiq_options retry: false

    def perform(task_id)
      task = Task.find(task_id)
      # Get the worker that's performing this job
      if worker = AppHelpers.find_worker(jid)
        # If the worker matches the "at" timestamp then this is the right one and we should execute it
        if worker.last["payload"]["at"].to_s.match(/(\d*\.\d{0,3})\d*/)[1] == task.start.to_f.to_s.match(/(\d*\.\d{0,3})\d*/)[1]
          task.execute
        else
          custom_logger.debug("This worker is the wrong one. Skipping...")
        end
      else
        custom_logger.error("We couldn't find the worker")
      end
    end
  end
end


module AppHelpers

  [...]

  def self.find_worker(jid)
    Sidekiq::Workers.new.select {|e| e.last["payload"]["jid"] == jid}.first
  end

  [...]

end

> task = Task.create(start: 5.hours.from_now)
> TaskStuff::TastSetter.perform_at(task.start, task.id)

现在如果我这样做

> task.update_attributes(start: 4.hours.from_now)
> TaskStuff::TastSetter.perform_at(task.start, task.id)

该任务将在 4 小时内执行,而另一个作业(将在 5 小时内执行)将在到达时间时被忽略并删除。

最初我尝试使用Time.now 而不是worker.last["payload"]["at"],但这可能非常不准确,因为计划的作业不会总是按时执行。检查间隔为 15 秒,如果所有工作人员都在其他地方忙,则作业可能会进一步延迟。

我必须使用Regexp 来匹配开始时间,因为在读取task.start 时,我可能会得到一个小数位数不同的浮点数,并且 if 条件不会通过。这样,我将两个值都设为小数点后 3 位。

我发现获取作业的“at”属性的唯一方法是通过工作人员获取它。如果我要问 Redis 或使用 Mike 的 Sidekiq::ScheduledSet.new,我不会得到当前的工作,因为它已经从 Redis 中撤出。

编辑 2:

对于任何感兴趣的人,我采用了类似但不同的方法。基本上,我没有比较 Task 的开始时间,而是在模型和 Sidekiq 调用中添加了一个额外的字段,称为 start_token。如果使用与对象相同的令牌调用了 sidekiq 作业,则它是有效的,否则丢弃并跳过该作业。每次模型更改 start_time 时都会更新令牌。

【问题讨论】:

  • 根据您的第二次编辑,这可能会有所帮助,因为我在工作中使用 ActiveRecord 对象,因此我使用的是 updated_at 字段。我用我的 ActiveRecord id 将它传递给我的工作,当我的工作开始时,我检查 updated_at 是否仍然相同

标签: ruby-on-rails ruby sidekiq


【解决方案1】:

这可能不是在回答问题,但这个问题首先在 google 上出现,用于“sidekiq 增加已安排工作的时间”。

Sidekiq 在 SortedEntry 作业中有此方法 (reschedule)。

找到工作:

job = Sidekiq::ScheduledSet.new.find_job(job_id)

重新安排工作:

job.reschedule(Time.now + 2.hours)

【讨论】:

  • 请注意,您还可以通过 Sidekiq::ScheduledSet.new.find { criteria }.at 查看特定作业的运行时间。 Documentation is here
【解决方案2】:

我不认为编辑/更新工作是一种方式。每次发生变化时,我通常都会创建新工作。然后在作业本身中检查执行某些任务的时间是否正确...如果时间正确,请继续执行该任务,否则跳过...

【讨论】:

  • 有趣的地方。我没想到。您是在使用当前时间 (Time.now) 来检查作业是否正确,还是有办法获取计划作业的确切开始时间?
  • 我建立在您的想法之上,并将我的代码放入问题正文中
  • 好的。 :) 对我而言,时间不是问题。日期就足够了。放一些代码,我们会看到..
【解决方案3】:

您还可以使用 job.reschedule() 方法来做一件事,另一种方法是删除您的第一个计划作业,然后使用新时间再次添加。

代码:

  bugs = @user.bugs
  queue = Sidekiq::ScheduledSet.new
  queue.each do |job|
    job.delete if bugs.ids.include? job.args.first
  end

这将删除与用户错误 ID 匹配的所有作业

【讨论】:

    猜你喜欢
    • 2018-02-07
    • 2021-01-21
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    相关资源
    最近更新 更多