chrishomer
chrishomer

Reputation: 4920

How do I find a specific delayed job (not by id)?

Delayed::Job serializes your class, method & parameters into the handler field. We currently resort to hardcoding this serialized method into our code. This is gross.

How should we be constructing the handler so we can look up an existing queued up job?

Upvotes: 7

Views: 5411

Answers (1)

Harish Shetty
Harish Shetty

Reputation: 64363

This what I do:

1) Add two new columns to delayed_jobs table

db/migrations/20110906004963_add_owner_to_delayed_jobs.rb

class AddOwnerToDelayedJobs < ActiveRecord::Migration
  def self.up
    add_column :delayed_jobs, :owner_type, :string
    add_column :delayed_jobs, :owner_id, :integer

    add_index :delayed_jobs, [:owner_type, :owner_id]
  end

  def self.down
    remove_column :delayed_jobs, :owner_type
    remove_column :delayed_jobs, :owner_id
  end
end

2) Add a polymorphic association to Delayed::Job model

config/initializers/delayed_job.rb

class Delayed::Job < ActiveRecord::Base
  belongs_to :owner, :polymorphic => true
  attr_accessible :owner, :owner_type, :owner_id
end

3) Monkey patch ActiveRecord::Base to contain a jobs association

config/initializers/active_record.rb

class ActiveRecord::Base
  has_many :jobs, :class_name => "Delayed::Job", :as => :owner
  def send_at(time, method, *args)
    Delayed::Job.transaction do
      job = Delayed::Job.enqueue(Delayed::PerformableMethod.new(self, 
             method.to_sym, args), 10, time)
      job.owner = self
      job.save
    end
  end

  def self.jobs
    # to address the STI scenario we use base_class.name. 
    # downside: you have to write extra code to filter STI class specific instance.
    Delayed::Job.find_all_by_owner_type(self.base_class.name)
  end
end

4) Triggering a jobs

class Order < ActiveRecord::Base

  after_create :set_reminders

  def set_reminders
    send_at(2.days.from_now, :send_email_reminder)
  end

  def send_email_reminder
  end

  # setting owner for handle_asynchronously notation.
  def foo
  end
  handle_asynchronously :foo, :owner => Proc.new { |o| o  }

end

5) Inspecting jobs

Order.jobs  # lists all the running jobs for Order class
order1.jobs # lists all the running jobs for Order object order1 

Upvotes: 16

Related Questions