在Rails 4.2中检查作业是否已经入队

rb-*_*rb- 5 ruby-on-rails delayed-job rails-activejob

我使用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
Run Code Online (Sandbox Code Playgroud)

如果作业的实例在再次调用时正在运行,则它应该仍然排队以备将来使用.我正在寻找一种方法让这项工作最终入组,最多可以运行1次.

我假设答案必须特定于delayed_job,但如果它可以推广到ActiveJob,那将更好.

小智 2

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

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
Run Code Online (Sandbox Code Playgroud)

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

Delayed::Job.where(queue: '<YOUR QUEUE>').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
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!