If you want to run longrunning jobs in the background, one very easy solution is using delayed_job. One other very interesting alternative is resque, but it seemed harder to setup (it uses redis), and delayed_job seemed to be just right for my needs.
In short (from the redis documentation) :
Choose Resque if:
- You need multiple queues
- You don’t care / dislike numeric priorities
- You don’t need to persist every Ruby object ever
- You have potentially huge queues
- You want to see what’s going on
- You expect a lot of failure / chaos
- You can setup Redis
- You’re not running short on RAM
Choose DelayedJob if:
- You like numeric priorities
- You’re not doing a gigantic amount of jobs each day
- Your queue stays small and nimble
- There is not a lot failure / chaos
- You want to easily throw anything on the queue
- You don’t want to setup Redis
And in my case: a short list of outstanding jobs, i am using a database already, not sure about redis, performance is not that important, i do not expect a lot of failure, i do not want to setup redis (yet :).
So to use the delayed_job gem in a rails3 you will need to use the code from github (as the gem version 2.0.3 is not yet rails3 compatible). Add the following line to your
gem "delayed_job", :git => 'git://github.com/collectiveidea/delayed_job.git'
and then run
Because i am using ActiveRecord, i can just use the generator, that will create the table and add the script to run a worker:
rails generate delayed_job rake db:migrate
Include the rake tasks from delayed-jobs into your
begin require 'delayed/tasks' rescue LoadError STDERR.puts "Run `bundle:install` to install delayed_job" end
Create an initializer file
delayed_jobs_config.rb and write
# config/initializers/delayed_job_config.rb Delayed::Worker.destroy_failed_jobs = false #Delayed::Worker.sleep_delay = 60 #Delayed::Worker.max_attempts = 3 Delayed::Worker.max_run_time = 5.minutes
If you are happy with the defaults, you can leave it. For me it was important to keep a record of the jobs that failed.
Then you can just delay any function-call like this:
Just adding the
.delay does all the magic for you! And starting a worker is as simple as