2scottish
2scottish

Reputation: 683

How to reference active delayed_job within the actual job

I am working on a solution to display the percentage completion of a delayed job (using the delayed_job gem). At the present, I have a database migration that looks like the following for my delayed_jobs table:

class CreateDelayedJobs < ActiveRecord::Migration
  def self.up
    create_table :delayed_jobs, :force => true do |table|
      table.integer  :priority, :default => 0      # Allows some jobs to jump to the front of the queue
      table.integer  :attempts, :default => 0      # Provides for retries, but still fail eventually.
      table.text     :handler                      # YAML-encoded string of the object that will do work
      table.text     :last_error                   # reason for last failure (See Note below)
      table.datetime :run_at                       # When to run. Could be Time.zone.now for immediately, or sometime in the future.
      table.datetime :locked_at                    # Set when a client is working on this object
      table.datetime :failed_at                    # Set when all retries have failed (actually, by default, the record is deleted instead)
      table.string   :locked_by                    # Who is working on this object (if locked)
      table.string   :queue                        # The name of the queue this job is in
      table.integer  :progress
      table.timestamps

    end

    add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
  end

  def self.down
    drop_table :delayed_jobs
  end
end

I am using an enqueue process within a controller method for a delayed job, and referencing a class in lib/build_detail.rb :

Delayed::Job.enqueue(BuildDetail.new(@object, @com))

The lib/build_detail.rb file is as follows:

class BuildDetail < Struct.new(:object, :com)

  def perform
    total_count = object.person_ids.length
    progress_count = 0

    people = com.person object.person_ids do |abc|
      progress_count += abc.size
      Delayed::Job.current.update_attribute :progress, (progress_count/total_count)
    end
  end  

end

Delayed::Job.current doesn't work. I see the Delayed::Job.current method proposed on this posting, however it looks like the method was never included in the main delayed_jobs github project.

How can I access the current job (from within the actual job), to update the progress field each time my job goes through the loop?

Upvotes: 5

Views: 2975

Answers (3)

hrdwdmrbl
hrdwdmrbl

Reputation: 5279

If you're also using ActiveJob, in an initializer, you can monkey patch the JobWrapper class.

module ActiveJob
  module QueueAdapters
    class DelayedJobAdapter
      class JobWrapper
        def perform(job)
        end
      end
    end
  end
end

Upvotes: 0

Aray Karjauv
Aray Karjauv

Reputation: 2945

It's to late to answer but I've faced with the same requirement so may be it will help someone. All you need to do is to implement custom job and before-hook where you will store reference on current job:

class MyTestJob
  def before(job)
    @job = job
  end

  def perform
    ...
    @job.update_attributes({ progress: your_progress_var }, without_protection: true)
  end
end

Upvotes: 10

Troy
Troy

Reputation: 5399

One of the cool things about delayed job is also what is thwarting you here. When you queue up lots of delayed jobs, you can work them off in parallel if you have multiple instances running workers - e.g. you could have 10 machines each running an instance of your app accessing the same database and get 10x speed boost of the processing. Because of that, there could be multiple "current" jobs. Having only one job running at a time is a bit of a special case.

Here's a way to see the status of all active jobs. If you only have one instance running, it will only return one job, so that will satisfy your situation:

active_jobs = Delayed::Job.where("progress > 0")
progress_of_first_job = active_jobs.first.progress if active_jobs.present?
progress_of_all_jobs = active_jobs.map{|job| job.progress}

progress_of_first_job is the progress of one of the jobs (use an order clause to be safe). progress_of_all_jobs is a (possibly empty) array of progress values for each active job.

Upvotes: 0

Related Questions