我使用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那就更好了。
答案 0 :(得分: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
因此,您可以向该表添加状态列,然后运行此类查询以获取作业并在执行任何其他操作之前检查其状态。
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
希望这有帮助!
答案 1 :(得分:1)
我发布了我最终做的事情,作为获得反馈的答案。这只是我测试的一种可能的解决方案。
在Job中我正在检查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
到目前为止,它不会让工作超出队列。缺点是我不知道我将缓存保持为最新状态。