No More Crontab Madness with a single Night Rake-Task

Crontab grows larger and larger with every new cleanup/maintence task…

...
0 0 1 * * cd ~/apps/my_app/current && RAILS_ENV=production rake summary:weekly_update >> ~/apps/my_app/current/log/summary_weekly_update.log
0 0 7 * * cd ~/apps/my_app/current && RAILS_ENV=production rake summary:weekly_update >> ~/apps/my_app/current/log/summary_weekly_update.log
0 0 14 * * cd ~/apps/my_app/current && RAILS_ENV=production rake summary:weekly_update >> ~/apps/my_app/current/log/summary_weekly_update.log
0 0 21 * * cd ~/apps/my_app/current && RAILS_ENV=production rake summary:weekly_update >> ~/apps/my_app/current/log/summary_weekly_update.log
...
echo 'crontab sucks...'

This is not DRY, so we fix it…

Cron calls “rake night” every night and night takes care of the rest…

#redirect and append puts to the logfile
def logging_to(path)
  FileUtils.touch([path])
  $stdout = File.new(path,'a+')
  yield
  $stdout = STDOUT
end

#use DRY to simulate a dry run
#uses hoptoad for error recording(better than exception notifier...), get it @ hoptoad.com
def invoke_and_log_task(name)
  begin
    logging_to "log/#{name.gsub(':','_')}.log" do
      if ENV['DRY']
        puts "dry-running #{name}"
      else
        Rake::Task[name].invoke
      end
    end
  rescue Exception => e
    HoptoadNotifier.notify(
      :error_class => "Nightly #{name} Error #{e.class}",
      :error_message => "#{e.message}"
    )
  end
end

desc "Runs maintains tasks at night"
task :night do
  invoke_and_log_task 'feed:update'
  invoke_and_log_task 'summary:weekly_update' if [1,7,14,21].include? Time.now.day
  ENV['greeting'] = 'Hello again...'
  invoke_and_log_task 'spam_users' if Time.now.day == 5
end

7 thoughts on “No More Crontab Madness with a single Night Rake-Task

  1. yeah thats right for this example.
    In general it is much more convenient to have one dead-simple cronjob running (e.g. once every night) that goes through ruby where all the logic sits and can be tested, and then is executed (with loging and failure notification) then having oh-so-clever cronjobs that are hard to maintain/understand/update.

  2. The alternative here would be to use the Whenever gem as well and have a schedule.rb built.

    It also fits nicely in with capistrano. I’ve added it to my 2.3 temp;ate since I end up using cron tasks all the time.

    I think this week’s RailsCast has a howto on it.

  3. yep, this can be done with whenever/schedule, but imo the beauty of the approach is that its dead-simple, everything stays in ruby and error notifications/logs are created

  4. Note that using the @weekly dealie in crontab is also an option.

    As an application developer, I might consider doing this. As a sysadmin, I start tearing my hair out when dealing with other people’s partial crontab reimplementations. 😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s