Craken

This is the first of hopefully many (a few?) Ruby on Rails plugins I’ve created as a developer for the Los Angeles Times.

This one is called Craken.  In a nutshell it manages and installs rake-centric cron jobs.  Coupled with Capistrano goodness it is the answer to your recurring task needs in Rails.

It’s up on GitHub: http://github.com/latimes/craken/tree/master

Here’s the deal: with many web applications comes the need to do recurring tasks on the servers the application runs on.  These sorts of tasks can range from running backups, clearing caches, emailing notices and other such maintenance-y things.

Who manages these tasks?  Ideally the task code as well as configuration and timing should be kept with the source code of the application itself and not as part of some further set of scripts that reside in a dubious location in your source control.  This is what Craken does.

The tasks are defined as rake tasks within the application.  Craken itself is a rake task that sets up a crontab for defined tasks based on your current application configuration.  The plugin also includes a Capistrano recipe that runs the Craken rake task on remote servers making deployment a breeze.

Craken, by default, looks for recurring task definitions here:

RAILS_ROOT/config/craken/crontab

You can also define tasks for a particular machine by prefixing the machine name (separated with an underscore):

RAILS_ROOT/config/craken/MyMachineName_crontab

The file format is modeled after crontab:

30 1 * * * thing:to_do

In this case thing:to_do is a rake task.  It will run at 1:30 AM every morning (take a look at the crontab format if this makes no sense).

The command to install the cron job locally:

% rake craken:install

If you’re using Capistrano for deployment (and you really should) a recipe is provided to run craken:install on remote machines.  Your Capistrano configuration needs to define a :cron role so the recipe knows which machines it should run the command on.

% cap craken:install

Ideally you can make craken:install part of your deployment configuration, :after_deploy would be a good place to put it.  Craken overwrites the existing configuration for the application on the machine so running it multiple times is not a problem.  Running multiple apps on the same machine or cron jobs placed by hand?  No worries, Craken delimits the lines it generates in crontab with comments and doesn’t disturb existing entries.

For more information about the plugin, peruse the README file.

If you have any questions/comments/suggestions about Craken please leave a comment!

The name “Craken” generously suggested by Giles Bowkett.

This entry was posted in Coding, Los Angeles Times, Plugins and tagged , , , , , , , , , . Bookmark the permalink.
  • http://micahcalabrese.com Micah Calabrese

    Very smart! I’m for sure going to use this on Making the Chain. What do you think about a friendlier format like a YML file? Maybe it’s just me but I alway have to read a crontab definition five times to be sure it’ll do what i think it’s going to do.

  • http://dougmcinnes.com Doug

    Awesome! Let me know how it works for you.
    YML might be an idea, I just can’t think of a better way to define recurring date/times (not to mention it makes translation to crontab format crazy easy). I guess I’m used to it too. Any ideas?

  • Pingback: Rails Cron — Craken « Gem Install That()

  • Pingback: A Fresh Cup » Blog Archive » Double Shot #264()

  • http://almosteffortless.com Trevor Turk

    Sweet. I’ve been looking for something like this. Much appreciated.

  • Pingback: Infovore » links for August 9th()

  • Pingback: Bookmarks for June 19th through June 28th at Logicola()

  • Robb Lovell

    If you do want to put a non-rake command in the cron file, you could make a convention where you add the word “direct” in the raketab in front of cron jobs you want to call that are not rake commands:

    direct 59 * * * * some_command > /tmp/log.log 2>&1

    Just change append_tasks in cracken.rb like this:

    def append_tasks(crontab, raketab)
    crontab << "### #{APP_NAME} raketab\n"
    raketab.each_line do |line|
    line.strip!
    unless line =~ /^#/ || line.empty? # ignore comments and blank lines
    sp = line.split
    direct = false
    if sp.first == "direct"
    sp.shift
    crontab << sp[0,5].join(' ')
    tasks = sp[5,sp.size]
    direct = true
    elsif SPECIAL_STRINGS.include?(sp.first)
    crontab << sp.shift
    tasks = sp
    else
    crontab << sp[0,5].join(' ')
    tasks = sp[5,sp.size]
    end
    if direct
    crontab << " cd #{DEPLOY_PATH} && "
    tasks.each do |task|
    crontab << " #{task}"
    end
    else
    crontab << " cd #{DEPLOY_PATH} && #{RAKE_EXE} –silent RAILS_ENV=#{RAKETAB_RAILS_ENV}"
    tasks.each do |task|
    crontab << " #{task}"
    end
    end
    crontab << "\n"
    end
    end
    crontab << "### #{APP_NAME} raketab end\n"
    crontab
    end

    I realize that it somewhat goes against why craken was written, but sometimes you do want to manage a non-rake command from rails.

  • http://tobiascohen.com/ Tobias

    Thanks, this is a great help in keeping application cron tasks organized.