Solving Background Processing with a Single, Generic Background Job

Again I read an article about background processing that generates many different jobs which all do the same: call method a on b with parameter z. At the moment we are using one GenericJob to handle all those cases.

It serializes ActiveRecord objects to a string representation, so that they do not get submittet as instance(often too large or deserialisation problems), if you do not need this feature, :send_later could be a good option for starting with generic jobs.

Usage

GenericJob.publish UserMailer, :deliver_notification,
  :args=>[user, comment], :priority=>2

Install

class GenericJob < DelayedJobBase
  DEFAULT_JOB_PRIORITY = 5

  # GenericJob.publish( Product, :find, :args=>[:all, {:conditions=>"1 = 2"}], :priority=>3 )
  def self.publish(klass, method, options={})
    args = options[:args] || []
    args = GenericJob.serialize_ar(args)
    priority = options[:priority] || DEFAULT_JOB_PRIORITY
    Delayed::Job.enqueue self.new(:class_name => klass.to_s, :method_name => method, :args => args), priority
  end

  def perform
    klass = message[:class_name].constantize
    args = GenericJob.deserialize_ar(message[:args]||[])
    klass.send(message[:method_name], *args)
  end

  private

  def self.serialize_ar(args)
    args.map do |arg|
      if arg.is_a?(ActiveRecord::Base)
        "ActiveRecord:#{arg.class}:#{arg.id}"
      else
        arg
      end
    end
  end

  def self.deserialize_ar(args)
    args.map do |arg|
      if arg.to_s =~ /^ActiveRecord:(\w+):(\d+)$/
        $1.constantize.find($2)
      else
        arg
      end
    end
  end
end

One thought on “Solving Background Processing with a Single, Generic Background Job

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s