当前位置: 首页 > 知识库问答 >
问题:

Ruby on Rails Sidekiq:如何改变一个预定的作业开始时间?

贲功
2023-03-14

我最近开始使用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小时内执行)将在到达时间时被忽略并删除。

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

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

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

编辑2:

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

共有3个答案

郗河
2023-03-14

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

代码:

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

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

梁泰
2023-03-14

我不认为编辑/更新工作是一种方式。每次事情发生变化时,我通常都会创造一份新工作。然后在作业本身中检查执行特定任务的时间是否正确…如果时间正确,继续执行任务,否则只需跳过。。。

张腾
2023-03-14

这可能没有回答这个问题,但这个问题首先在谷歌上出现,因为“sidkiq增加已安排工作的时间”。

Sidekiq 在 SortedEntry 作业上有此方法(重新调度)。

找到工作:

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

重新安排工作:

job.reschedule(Time.now + 2.hours)
 类似资料:
  • 我试图设置一个cron作业,该作业将在工作日上午9:45到下午4点之间每分钟运行一次。 很容易让它在上午 9 点到下午 4 点之间工作,但让它在 9:45 开始给我带来了问题。 我试过: < code>45/1 9-16 * * 1-5 但是这将返回一个错误,16:错误的分钟

  • 问题内容: 1.问题 例如,有没有一种方法可以从小部件列表ListView.builder的第二个(index = 1)项目开始? 就我而言,我正在尝试在a的顶部添加一些空白区域,ListView以便用户可以将顶部卡片滚动到更靠近他的拇指的位置。一种解决方法是Container在List小部件的顶部和底部添加empty ,以模拟空白空间。但是,将在屏幕上显示,用户可能会感到困惑,并且不知道仅通过滚

  • 如果一项工作没有在10分钟内完成,在接下来的10分钟内另一项工作将开始。 我想要的是:下一个作业(每10分钟后)应该启动,只有在前一个作业已经完成运行的情况下。有什么办法可以做到吗?

  • 我希望能够用REST控制器开始我的作业,然后当作业开始时,它应该在计划的基础上运行,直到我用REST再次停止它。

  • 我有一个enum,其值如下:,,等。 我试图编写一个方法,它接受并返回该时间段的开始和结束日期。 我研究了新的Java8类,该类可能需要一个开始时间和结束时间,但似乎没有任何干净的方法可以在之后检索这些值。 如果不使用(似乎是错误的数据结构)或一些难看的日期时间算法,我如何能一次干净地返回开始日期和结束日期?

  • 问题内容: 我一直在使用Django开发网络应用,而我很好奇是否有一种方法可以安排作业定期运行。 基本上,我只想遍历数据库并定期自动进行一些计算/更新,但是我似乎找不到任何有关此操作的文档。 有人知道如何设置吗? 需要说明的是:我知道我可以为此设置工作,但我很好奇Django中是否有某些功能可以提供此功能。我希望人们能够自己部署此应用程序,而无需进行大量配置(最好为零)。 我已经考虑过通过简单地检