unique_delayed_job

Overview

You must have delayed_job installed as a gem or plugin to use this class.

Class for creating delayed jobs that can be de-duped with existing delayed jobs already in the delayed jobs table. You just specify some additional columns on your delayed_jobs table and set them to have uniqueness constraints. Then specify these column values when you create a UniqueDelayedJob and if a duplicate key is raised on insert, then the insert will just be ignored. There are factory methods for creating a delayed job in the following ways:

  • with a delayed job handler class (one that responds to perform())

  • with an object, method and method arguments

  • with a string to be evaled see the Delayed::Job.enqueue() method that accepts a block. (looks like the idea may have been added to delayed job here: github.com/dhh/delayed_job/commit/89c3a0b77470c0f8510d3c7a51a36cd07747d9a9) the block is yielded to, and the result (assumed to be a string) is stored as the code to be evaled when the job is deserialized.

Configuration

You can add whatever columns you need to the delayed_jobs table, and put any uniqueness constraints (or not) on them as you wish (unique columns, unique composite keys etc.).

Note that by default, UniqueDelayedJob will modify any jobs that are currently locked (locked_by is not null)…it will set all of the additional columns specified on the job to NULL. (This allows for inserting a new job if a matching job is already in process–and thus might be using out-of-date data.) If you do NOT want this behavior, and do not want to insert a matching job if another job is currently locked/being run, then make the following call. If you like, you can change this before/after every job you insert if you want different jobs to use different policies.

UniqueDelayedJob.do_not_mark_locked_jobs_with_null()

Examples

In each example below, the :user_id => 123 is just to illustrate that you can add arbitrary additional column(s) to the delayed job row being inserted. Presumably, the user_id column has uniqueness constraints on it…

(More than one column could be specified; uniqueness is enforced by the db schema, and unique delayed job just catches and swallows any duplicate key exceptions.)

# use a custom handler
job = Delayed::UniqueDelayedJob.use_handler(MyHandlerClass.new( ...), :user_id => 123)
job.enqueue  # use default priority and run_at

# use a method call (similar to using send_later on the object)
record = MyActiveRecord.find(1)
job = Delayed::UniqueDelayedJob.call_method(record,
                                            :a_method,
                                            [arg1, arg2],
                                            :user_id => 123)
job.enqueue(1) # use priority of 1

# specify a block of code to execute with string (inside a block)
# note that the block could be complex logic that results in a string that is
# arbitrary ruby code to be evaled
# see Delayed::Job::enqueue(args, &block)
job = Delayed::UniqueDelayedJob.run_eval(:user_id => 123) do
  'SomeClass.perform_some_slow_action'
end
job.enqueue(2, 1.hour.from_now) # run with priority 2 and run at 1 hour from now