Skip to content

DelayedJob

ed-mare edited this page Feb 26, 2019 · 6 revisions

Articles

Order of Execution

DelayedJob

The order of callback calls for a successful job execution is:

  • before
  • perform (to do the real work of the job)
  • success
  • after

The order of callback calls for a failed job execution is:

  • before
  • perform (to do the real work of the job)
  • error
  • after
  • failure

Hooks are used in your job class:

class ParanoidNewsletterJob < NewsletterJob
  def enqueue(job)
    record_stat 'newsletter_job/enqueue'
  end

  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  # If you need the job in perform, add a before callback and assign job  
  # to an instance variable. i.e., @job is available in perform.
  def before(job)
    @job = job
    record_stat 'newsletter_job/start'
  end

  def after(job)
    record_stat 'newsletter_job/after'
  end

  def success(job)
    record_stat 'newsletter_job/success'
  end

  def error(job, exception)
    Airbrake.notify(exception)
  end

  def failure(job)
    page_sysadmin_in_the_middle_of_the_night
  end
end

ActiveJob

ActiveJob callbacks are:

  • before_enqueue
  • after_enqueue
  • around_enqueue
  • before_perform
  • after_perform
  • around_perform

DelayedJob callbacks != ActiveJob callbacks

As of Rails 5.2.1 and DelayedJob (4.1.3 active record), after_perform DOES NOT execute when an exception is thrown. DelayedJob's after callback is better because it's always called.

Lifecycle

Global hooks can be added with DelayedJob plugins. Events are:

EVENTS =
{
  :enqueue    => [:job],
  :execute    => [:worker],
  :loop       => [:worker],
  :perform    => [:worker, :job],
  :error      => [:worker, :job],
  :failure    => [:worker, :job],
  :invoke_job => [:job]
}.freeze

Example:

require 'delayed_job'

# In delayedjob initializer, add like so: Delayed::Worker.plugins << DelayedJob::XyzPlugin 
module DelayedJob
  class XyzPlugin < Delayed::Plugin

    # worker = instance of Delayed::Worker
    # job = instance of Delayed::Backend::ActiveRecord::Job
    # job.payload_object - is an instance of the job class stored in handler column

    callbacks do |lifecycle|
      
      lifecycle.before(:invoke_job) do |job, *args, &block|
        # do something before invoking job
      end

      lifecycle.after(:perform) do |worker, job|
       # do something after performing the job
      end
      
    end
    
  end
end

Priority

  • The lower the number the higher the priority.
  • 0 is the lowest. Don't assign to a queue -- reserve to force a job to the top when needed.
  • A default priority can be assigned to a queue. Example:
# Add to delayjob initializer
Delayed::Worker.queue_attributes = {
  default: { priority: 5 },
  foo: { priority: 1 },
  bar: { priority: 2 },
  baz: { priority: 3 }
}

Commands

Delayed::Worker docs

# execute specific job and remove job afterwards
Delayed::Worker.new.run( Delayed::Job.find(x) ) 

# execute specific job but not remove job 
Delayed::Job.find(x).invoke_job

# work off all jobs 
Delayed::Worker.new.work_off

# execute n jobs
Delayed::Worker.new.work_off(n)

# only specific queues
Delayed::Worker.new(queues: ['my_queue']).work_off

# execute specific jobs with proc
Delayed::Worker.delay_jobs = ->(job) {
  job.run_at && job.run_at > Time.now.utc
}

# Delay all jobs. Jobs get queued.
Delayed::Worker.delay_jobs = true

# Immediately execute jobs.
Delayed::Worker.delay_jobs = false

# Get last job 
Delayed::Job.last

Clone this wiki locally