Rails 4.2从活动作业中获得延迟的作业ID

知道如何从ActiveJob入队获取Delayed::Job id吗? 当我排队工作时,我用@job_id返回一个ActiveJob::Base的实例,但该工作ID似乎是ActiveJob的内部。 到目前为止,我最好的猜测就是走下最近创建的工作:

 active_job_id = GenerateReportJob.perform_later(self.id).job_id delayed_job = Delayed::Job.order(id: :desc).limit(5).detect do |job| YAML.load(job.handler).job_data['job_id'] == active_job_id end 

但这似乎是各种各样的hacky。 有点惊讶的ActiveJob没有从Delayed::Job返回ID,特别是因为这是在作业入队时显式返回的内容。

==编辑

看起来我不是唯一一个( https://github.com/rails/rails/issues/18821 )

如果有人在将来发现这个:Rails刚刚接受了一个补丁,允许你从Rails 5中的provider_job_id获取这个id。你可以使用像这样的补丁来使用它

 ActiveJob::QueueAdapters::DelayedJobAdapter.singleton_class.prepend(Module.new do def enqueue(job) provider_job = super job.provider_job_id = provider_job.id provider_job end def enqueue_at(job, timestamp) provider_job = super job.provider_job_id = provider_job.id provider_job end end) 

受到Beguene的回答以及Rails 5 ActiveJob代码的一些逆向工程的启发,我已经使它与Rails 4.2一起使用了

1)在lib/active_job/queue_adapters/delayed_job_adapter.rbconfig/initializers/delayed_job.rb添加以下代码(两个位置都有效):

 # file: lib/active_job/queue_adapters/delayed_job_adapter.rb module ActiveJob module Core # ID optionally provided by adapter attr_accessor :provider_job_id end module QueueAdapters class DelayedJobAdapter class << self def enqueue(job) #:nodoc: delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name) job.provider_job_id = delayed_job.id delayed_job end def enqueue_at(job, timestamp) #:nodoc: delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp)) job.provider_job_id = delayed_job.id delayed_job end end class JobWrapper #:nodoc: attr_accessor :job_data def initialize(job_data) @job_data = job_data end def perform Base.execute(job_data) end end end end end 

Rails 4.2中需要attr_accessor :provider_job_id语句,因为它在enqueue方法中使用,但尚未在4.2中定义。

然后我们可以使用它如下:

2)定义我们自己的ActiveJob类:

 # file: app/jobs/my_job.rb class MyJob < ActiveJob::Base queue_as :default def perform(object, performmethod = method(:method)) # Do something later returnvalue = object.send(performmethod) returnvalue end end end 

3)现在我们可以在代码中的任何地方创建一个新工作:

 job = MyJob.perform_later(Myobject, "mymethod") 

这将把方法Myobject.mymethod放入队列中。

4)1)中的代码帮助我们找到与我们的工作相关的延迟工作:

 delayed_job = Delayed::Job.find(job.provider_job_id) 

5)最后,无论我们需要对delayed_job做什么,我们都可以做,例如删除它:

 delayed_job.delete 

注意:在Rails 5中,不再需要步骤1),因为完全相同的代码是Rails 5的组成部分。

我使用Rails 5中的新补丁使其在Rails 4.2中工作,如下所示:

创建文件lib/active_job/queue_adapters/delayed_job_adapter.rb

 module ActiveJob module QueueAdapters class DelayedJobAdapter class << self def enqueue(job) #:nodoc: delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name) job.provider_job_id = delayed_job.id delayed_job end def enqueue_at(job, timestamp) #:nodoc: delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp)) job.provider_job_id = delayed_job.id delayed_job end end class JobWrapper #:nodoc: attr_accessor :job_data def initialize(job_data) @job_data = job_data end def perform Base.execute(job_data) end end end end end 

如果作业被取消,您可以模拟取消作业本身,而不是从队列中删除作业。

然后,当您运行GenerateReportJob您可以首先检查报告是否取消。 如果有,那么您可以销毁取消记录并退出报告生成。 如果没有取消,那么你可以照常进行。