rake - A cron job for rails: best practices?

ID : 10126

viewed : 23

Tags : ruby-on-railsrakedaemoncronrunnerruby-on-rails

Top 5 Answer for rake - A cron job for rails: best practices?

vote vote

96

I've used the extremely popular Whenever on projects that rely heavily on scheduled tasks, and it's great. It gives you a nice DSL to define your scheduled tasks instead of having to deal with crontab format. From the README:

Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.

Example from the README:

every 3.hours do   runner "MyModel.some_process"          rake "my:rake:task"                    command "/usr/bin/my_great_command" end  every 1.day, :at => '4:30 am' do    runner "MyModel.task_to_run_at_four_thirty_in_the_morning" end 
vote vote

86

I'm using the rake approach (as supported by heroku)

With a file called lib/tasks/cron.rake ..

task :cron => :environment do   puts "Pulling new requests..."   EdiListener.process_new_messages   puts "done." end 

To execute from the command line, this is just "rake cron". This command can then be put on the operating system cron/task scheduler as desired.

Update this is quite an old question and answer! Some new info:

  • the heroku cron service I referenced has since been replaced by Heroku Scheduler
  • for frequent tasks (esp. where you want to avoid the Rails environment startup cost) my preferred approach is to use system cron to call a script that will either (a) poke a secure/private webhook API to invoke the required task in the background or (b) directly enqueue a task on your queuing system of choice
vote vote

78

In our project we first used whenever gem, but confronted some problems.

We then switched to RUFUS SCHEDULER gem, which turned out to be very easy and reliable for scheduling tasks in Rails.

We have used it for sending weekly & daily mails, and even for running some periodic rake tasks or any method.

The code used in this is like:

    require 'rufus-scheduler'      scheduler = Rufus::Scheduler.new      scheduler.in '10d' do       # do something in 10 days     end      scheduler.at '2030/12/12 23:30:00' do       # do something at a given point in time     end      scheduler.every '3h' do       # do something every 3 hours     end      scheduler.cron '5 0 * * *' do       # do something every day, five minutes after midnight       # (see "man 5 crontab" in your terminal)     end 

To learn more: https://github.com/jmettraux/rufus-scheduler

vote vote

70

Assuming your tasks don't take too long to complete, just create a new controller with an action for each task. Implement the logic of the task as controller code, Then set up a cronjob at the OS level that uses wget to invoke the URL of this controller and action at the appropriate time intervals. The advantages of this method are you:

  1. Have full access to all your Rails objects just as in a normal controller.
  2. Can develop and test just as you do normal actions.
  3. Can also invoke your tasks adhoc from a simple web page.
  4. Don't consume any more memory by firing up additional ruby/rails processes.
vote vote

60

The problem with whenever (and cron) is that it reloads the rails environment every time it's executed, which is a real problem when your tasks are frequent or have a lot of initialization work to do. I have had issues in production because of this and must warn you.

Rufus scheduler does it for me ( https://github.com/jmettraux/rufus-scheduler )

When I have long jobs to run, I use it with delayed_job ( https://github.com/collectiveidea/delayed_job )

I hope this helps!

Top 3 video Explaining rake - A cron job for rails: best practices?

Related QUESTION?