Delayed Job is great for offloading processes out of the way for users.
For Heraldr, we needed to be able to send a lot of emails from the site without bogging down the performance.
Enter Delayed Job. It uses a table in the db to store jobs in a que to be processed in the background.
This is helpful because the data is stored in the db and will not be lost if there is a server hiccup (as is a danger with other rails background processes).
We looked at different options, but Delayed Job worked best for what we needed.
We also recommend using the plugin instead of the gem. It worked a little smoother in dev mode.
How to use Delayed Job
Install the plugin from git hub into your plugins folder.
ruby script/plugin install git://github.com/tobi/delayed_job.git
Once you have installed the plugin you need to create a Delayed Job Migration and add the jobs table to the database.
ruby script/generate migration create_table_for_delayed_job #in the migration file class CreateTableForDelayedJob < ActiveRecord::Migration def self.up create_table :delayed_jobs, :force => true do |t| t.integer :priority, :default => 0 t.integer :attempts, :default => 0 t.text :handler t.string :last_error t.datetime :run_at t.datetime :locked_at t.datetime :failed_at t.string :locked_by t.timestamps end end def self.down drop_table :delayed_jobs end end rake db:migrate
Now that you have a delayed_job table, you have options on how to add jobs to the que.
For the easiest way, you can simply add:
Model.send_later(:method, object, second object if necessary)
This will use the plugin defaults in the delayed_job folder for the amount of time delayed, etc.
You can also create a custom class to handle the processing instead of using send_later() like:
class NewsletterJob < Struct.new(:text, :emails) def perform emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) } end end #Use this in where you need to call the Delayed Job task Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
This example is from the readme file, which does a pretty good job of explaining everything.
The class just acts as a custom wrapper to enque the tasks you need to run in the background.
With the latest version, you can have multiple Delayed_job workers running as long as they are separate (and you have the system rescources).
Running the worker
In dev mode, it is easy to run:
rake jobs:work
Delayed Job will then cycle through the table sending one job at a time.
rake jobs:clear
Will remove all jobs from the db.
In production, you can write a script to start and stop the worker upon deploying.
After a few tries and a couple different gems and methods, we found Amit Mathur's script used with the daemon-spawn gem to be most effective.
Just create a delayed_job file in the /scripts folder and copy the code there.
Be sure to add github to your gem sources if you have not already for the daemon-spawn gem.
sudo gem sources -a http://gems.github.com sudo gem install alexvollmer-daemon-spawn
daemon-spawn proved to be more stable and easier to work with then the daemon gem.
Amit also has a very good Delayed Job tutorial on Delayed Job that is worth reading.
Amit also quotes CollectiveIdea's Cap recipe which worked well.
Just add it to the end of your deploy.rb file.
# add this to config/deploy.rb namespace :delayed_job do desc "Start delayed_job process" task :start, :roles => :app do run "cd #{current_path}; script/delayed_job start #{rails_env}" end desc "Stop delayed_job process" task :stop, :roles => :app do run "cd #{current_path}; script/delayed_job stop #{rails_env}" end desc "Restart delayed_job process" task :restart, :roles => :app do run "cd #{current_path}; script/delayed_job restart #{rails_env}" end end after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart"
The most difficult part is setting up the worker for production. Delayed Job pretty much works out of the box in dev mode.
Be sure the rake command works first in production mode by entering the rake command on the server's command line to confirm that Delayed Job can connect to the db.
/.../app/ rake jobs:work
Then try the the script/daemon combo.