Delayed Job Best Practices

I have been using Delayed Job quite a lot at my current job at FFX. And I have encountered some interesting and hard to debug issues with it.

I am outlining some of few best practices that hopefully makes your life with DJ easier:

Read Delayed Job common problems

Go on, go there first - I’ll wait :): Delayed Job common problems

Run Delayed Job worker on your dev environment

If you don’t run Delayed Job worker on your dev environment, you are bound to find surprises when you deploy your code to staging or production - trust me :)

At work, we used to have this our delayed job initializer:

Delayed::Worker.delay_jobs = !(Rails.env.development? || Rails.env.test?)%

This means that on development and test environment, jobs are executed immediately by the same server that schedules the job, in other words, NOT delayed.

While it is a sensible setting for test environment, it is not probably not a good idea for dev.

Why?

Because by doing this, you are not adhering to maintaining Dev/prod parity. Where there is a parity gap between environments, bad and unexpected things tend to happen.

Set destroy_failed_jobs to false

If you ever encountered an issue where you think your job has been run successfully but you just can’t see the effect of the job.

For example, you have a delayed job that sends out email - the email never gets sent, but the job is not reported as error. Even more confusing you check on your delayed_jobs table - the job is not there.

Well, in this case I’d want to suggest that the DJ failed even before running your job.

DJ has this behavior in that when it fails to parse the YAML code in the handler, it will just remove the job from delayed_jobs table. This is the only time when I ever encountered this behavior.

You can do the following to prevent the removal of the job (this is from the common problems link above):

Delayed::Worker.destroy_failed_jobs = false

Honestly, I think this config should default to true, but anyway.

Pass simple values as parameters to the job

Related to the issue above, the failure to parse YAML can sometime be caused by the parameters that you send to your job.

It is best to keep your job to accept simple values as parameters.

For example, you have a job that sends email to a user and your job might be like this:

class MarketingMailer
  def initialize(member)
    @member = member
  end

  def perform
    ...
  end
end

I would suggest that instead of initializing the job with member object, pass in a member identifier instead (e.g member_id)

For example:

class MarketingMailer
  def initialize(member_id)
    @member = Member.find(member_id)
  end

  def perform
    ...
  end
end

Conclusion

That is all I got - happy hacking!