【问题标题】:In Rails 4.2 check if a job is already enqueued在 Rails 4.2 中检查作业是否已经入队
【发布时间】:2015-04-18 08:13:31
【问题描述】:

我使用 Rails 4.2 和 delayed_job 4.0.6 作为我的 ActiveJob 后端。

我有一份工作,我只想在队列中允许一次。有问题的作业需要一分钟多的时间才能运行。它由模型上的回调排队。回调将比作业完成的频率高得多。该作业无需在未来多次排队。

这是我想要完成的一些伪代码。

# app/jobs/refresh_account_cache_job.rb
class RefreshAccountCacheJob < ActiveJob::Base
  def before_enqueue
    skip if job_already_enqueued
  end

  def perform
    Account.write_to_cache
  end

  def job_already_enqueued
    # ?
  end
end

如果作业的实例在再次调用时正在运行,它仍应排队等待将来。我正在寻找一种方法让该作业排队等待未来最多运行 1 次。

我认为答案必须特定于delayed_job,但如果它可以推广到ActiveJob,那就更好了。

【问题讨论】:

  • 可以用redis吗?比如,你的堆栈上安装了吗?
  • 我需要在这个项目上坚持使用 Postgres。
  • 不是要求你替换它,但是如果你可以将redis和Postgres一起使用,可以有一个简单的解决方案。
  • 如果你在考虑 Resque 或 Sidekiq,我不能走这两条路。
  • 不.. 保持一切不变,只需将 redis 添加到堆栈中,这样您就可以对其进行简单的获取/设置。

标签: ruby-on-rails delayed-job rails-activejob


【解决方案1】:

这可能不完全适合,但它应该让你指向正确的方向:

def self.up
  create_table :delayed_jobs, :force => true do |table|
  table.integer  :priority, :default => 0, :null => false
  table.integer  :attempts, :default => 0, :null => false
  table.text     :handler,                 :null => false
  table.text     :last_error
  table.datetime :run_at
  table.datetime :locked_at
  table.datetime :failed_at
  table.string   :locked_by
  table.string   :queue
  table.timestamps
end

因此,您可以在该表中添加一个状态列,然后运行这样的查询来获取作业并在执行其他任何操作之前检查其状态。

Delayed::Job.where(queue: '&lt;YOUR QUEUE&gt;').where(id: params[:id]).status

你会问,你会如何设置状态?好吧,在延迟的工作中使用成功钩子。它看起来有点像这样:

def success(job)
  update_status('success')
end

private

def update_status(status)
  job = Job.find job_id
  job.status = status
  job.save!
end

希望这会有所帮助!

【讨论】:

  • 我试试看。
【解决方案2】:

我将发布我最终所做的事情作为答案,以获得有关它的反馈。这只是我正在测试的一个可能的解决方案。

在作业中,我正在检查 Delayed::Job 列表以查看当前处理程序是否存在。如果是,我会跳过这份工作。

# queue_job.rb
class EnqueueJob < ActiveJob::Base
  queue_as :default

  def already_enqueued?
    Delayed::Job.all.any? do |job|
      job.handler.include?("EnqueueJobHandler")
    end
  end

  def perform
    unless already_enqueued?
      # do stuff
    end
  end
end

到目前为止,它一直在防止作业超出队列。缺点是我不知道我是否将缓存保持为我想要的最新状态。

【讨论】:

  • 此解决方案不可扩展,因为您正在循环所有作业。您应该使用 ActiveRecord 来利用数据库,就像上面建议的解决方案一样:Delayed::Job.where(queue: '').any?
猜你喜欢
  • 2015-10-23
  • 2018-06-15
  • 2013-05-06
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 2015-04-19
  • 2010-12-07
  • 2019-04-12
相关资源
最近更新 更多