简体   繁体   English

Ruby on Rails + Sidekiq:如何更改预定的作业开始时间?

[英]Ruby on Rails + Sidekiq: How do I change a scheduled job start time?

I started working with Sidekiq recently and noticed that it has an awesome feature that I've been searching for a long time:我最近开始使用 Sidekiq 并注意到它有一个很棒的功能,我一直在寻找它:

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

Basically I can schedule a job in the future so I don't need my app to poll continuously for new events with a start time.基本上我可以在未来安排工作,所以我不需要我的应用程序连续轮询具有开始时间的新事件。

Now this works like a charm, but how do I change the start time of a job?现在这就像一个魅力,但我如何更改工作的开始时间? Often some scheduled events will have their start time changed.通常,某些预定事件的开始时间会更改。 How do I replicate this in sidekiq?我如何在 sidekiq 中复制这个?

I know I can delete the job and create a new one, but is it possible to just modify the start time?我知道我可以删除作业并创建一个新作业,但是否可以只修改开始时间?

EDIT :编辑

I built upon Oto Brglez's idea and here is the documented code:我建立在 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)

Now if I do this现在如果我这样做

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

the task will get executed in 4 hours and the other job (that will get executed in 5 hours) will get ignored and removed when it reaches it's time.该任务将在 4 小时内执行,而另一个作业(将在 5 小时内执行)将在到达时间时被忽略并删除。

Initially I tried using Time.now instead of worker.last["payload"]["at"] but that could have been pretty inaccurate because a scheduled job will not always get executed on time.最初我尝试使用Time.now而不是worker.last["payload"]["at"]但这可能非常不准确,因为预定的作业不会总是按时执行。 There is a check interval of 15 seconds, and if all workers are busy elsewhere, the job could be delayed further.有 15 秒的检查间隔,如果所有工人都在其他地方忙,则作业可能会进一步延迟。

I had to use Regexp for matching the start time because when reading the task.start I might have gotten a float with a different number of decimals and the if condition would not pass.我不得不使用Regexp来匹配开始时间,因为在读取task.start我可能得到了一个具有不同小数位数的浮点数,并且 if 条件不会通过。 This way I'm getting both values to 3 decimal.通过这种方式,我将两个值都设为小数点后 3 位。

I found that the only way of getting the "at" attribute of the job is by getting it through the worker.我发现获得工作的“at”属性的唯一方法是通过工人获得它。 If I were to ask Redis or use Mike's Sidekiq::ScheduledSet.new I would not get the current job because it would have already been pulled out of Redis.如果我问 Redis 或使用 Mike 的Sidekiq::ScheduledSet.new我不会得到当前的工作,因为它已经从 Redis 中删除了。

EDIT 2 :编辑 2

For anyone interested, I went with a similar but different approach.对于任何感兴趣的人,我采用了类似但不同的方法。 Basically instead of comparing the start time of the Task , I added an extra field to the model and Sidekiq call, called start_token .基本上,我没有比较Task的开始时间,而是在模型和 Sidekiq 调用中添加了一个额外的字段,称为start_token If the sidekiq job has been called with the same token that the object has then it's valid, otherwise discard and skip the job.如果使用与对象相同的令牌调用了 sidekiq 作业,则它是有效的,否则丢弃并跳过该作业。 The token gets updated every time the model changes start_time.每次模型更改 start_time 时都会更新令牌。

This is probably not answering the question, but this question is first on google for "sidekiq increase the time of an already scheduled job".这可能没有回答这个问题,但这个问题首先出现在谷歌上,用于“sidekiq增加已安排工作的时间”。

Sidekiq has this method( reschedule ) on a SortedEntry job. Sidekiq 在 SortedEntry 作业上有这个方法( reschedule )。

Find the job:找工作:

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

reschedule the job:重新安排工作:

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

I dont think editing/updating jobs is the way.我不认为编辑/更新工作是方法。 I usually create new job each time something changes.每次发生变化时,我通常都会创建新工作。 And then in the job itself check if the time to execute certain task is right... If the time is right, continue with the task otherwise just skip...然后在作业本身检查执行某个任务的时间是否正确......如果时间合适,继续执行任务,否则跳过......

You can also do one thing by using a job.reschedule() method and the other way to do this is to delete your first scheduled job and then add again with the new time.您还可以使用 job.reschedule() 方法做一件事,另一种方法是删除您的第一个计划作业,然后使用新时间再次添加。

Code:代码:

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

This will delete all the jobs which matched the user bugs ids这将删除与用户错误 ID 匹配的所有作业

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM