Rails has several popular options for queuing or scheduling tasks. When I was looking at the alternatives for my app TimeVault I was faced with something of a difficult choice. Two of the most popular libraries, Resque and Sidekiq, require Redis. At the time, I didn’t want to mess around with an additional component to deploy, so I used Delayed::Job instead.
Delayed::Job (DJ) supports multiple backends. Most importantly for our purposes, it has solid support for ActiveRecord. There are performance reasons for choosing Redis over ActiveRecord, but for a small learning app these are typically safe to ignore.
TimeVault allows users to set Pomodoro timers and receive alerts when they are complete. Each timer has one or more Intervals with a start and stop time. When a timer starts, an Interval is created, which then creates an
def create_interval_worker Delayed::Job.enqueue(IntervalWorker.new(id), run_at: when_to_run) save end
DJ supplies an
enqueue class method. Here, I’m passing in a new
IntervalWorker and using the
run_at option to delay instantiation of the worker until the interval expires. DJ expects enqueued objects to have a
perform method that will be called on execution. Here, the
complete! on the interval that created it.
class IntervalWorker def initialize(interval_id) @interval_id = interval_id end def perform interval = Interval.where(id: @interval_id).first interval.complete! if interval.present? end end
complete! ends the interval by setting its
end attribute to the current time. Note how the service object,
IntervalWorker, is quite simple. All the actual logic is built into the model,
Interval. This is an example of separation of concerns. Modifying the
Interval is not a concern of the
I highly recommend the Delayed::Job RailsCast to get started with DJ. Good luck!