views:

513

answers:

5

I am currently writing an application that pulls new information from RSS sources and has to update those RSS sources in a certain frequency. Currently I am pulling only when the user requests a feed but I want to change that behavior to automatic periodic fetching.

I was writing a shellscript that would interact with the database and gets started periodically via cron - but this is lots of double effort so I was wondering what would be the "Rails Way" or "Ruby Way" to do this. I am using Ubuntu, Apache and Passenger. Can you suggest better methods that are maybe even included in the application, so I can easily deploy the app to another machine without having to mingle with cron?

A: 

There are a variety of solutions. For the simplest setup, you can use script/runner in your crontab something like so:

10 0 * * * /home/myuser/myproject/script/runner -e production ModelName.methodname

Methodname must be a static method on your model. You need to reference the project by full path, otherwise it will not be found most likely in the cron environment. Check your crontab man page for info on the crontab syntax if you're not familiar. The above, for example, runs the script at the 10th minute of the 0th hour of every day (at 12:10am, in short).

If you need a more powerful solution, you could use BackgroundRB. BackgroundRB runs a daemon and supports tasks that schedule, and can put results in a database. They even have a simple communication protocol to allow your web processes to request a task be completed, and then have a way to retrieve the result. This allows you to control background jobs right from the web interface, rather than a crontab which just "happens".

There is a good bit more setup needed for BackroundRB to work, but it may be worth it if jobs need to be controlled.

Crast
+10  A: 

I would suggest doing something like a rake task and using the whenever gem to generate your cron job to run the rake task.

Check out, http://railscasts.com/episodes/164-cron-in-ruby, for more information on the whenver gem.

The main benefit of the whenever gem is that it keeps your application requirements (i.e. the cron job running every x hours, in the application) inside your application, increasing the portability of your application.

Travis
To nitpick a bit: the gem is called 'whenever', not 'whenver'.
mtyaka
Thanks ... I was falling asleep answering that question :D
Travis
+3  A: 

I recommend a combination of the two above. You want a rake task, even if you have a direct method already created. This is because server admin stuff that you'd want to run in cron, you might also want to run from the command line occasionally, and this is what rake tasks are good for.

The whenever plugin sounds cool, although I can't vouch for it. Of course, it's good to know how to do things from scratch, then use plugins to make your life easier. Here's the from-scratch way.

Create a new file, lib/tasks/admin.rake

Inside, create the task itself:

namespace :admin
  desc "Updates all RSS feeds"
  task :rss => :environment do
    RssFeed.update_all
  end
end

This assumes you have an RssFeed class, and the update_all method does what you'd expect. You can call this from the command line:

rake admin:rss

And you can add this to cron (by calling crontab -l as the web user) and adding this line:

10 0 * * * cd /path/to/rails/app && rake RAILS_ENV=production admin:rss
Jaime Bellmyer
You make a good point in knowing how to do things manually. The main benefit of the whenever gem though, as I pointed to above, is not only is the syntax of writing a cron job cleaner, because of the dsl it uses, but it allows you to keep that business requirement ( the cron job ), in version control with your application, that way when the time comes to scale up, you don't have to go hunting through the cron tab, copying the cron tab, filtering out other cron jobs unrelated to your app, changing paths, etc.You can just generate the additions to the crontab with the gem.
Travis
I totally agree, and I'll definitely checkout that gem for myself! You're right, expected crons *should* be a part of the application, included in version control, etc. I just thought I'd contribute a bit of a foundation.
Jaime Bellmyer
A: 

Try using whenever. Eventhough in the end it will create a cron, but the scheduling definition will be written inside your application using Ruby DSL.

jpartogi
A: 

For small teams and personal projects, the whenever gem is great. But if your company has an ops team separate from the development team, it might not be ideal.

At my last job, the ops team needed to be able to see the cron we were installing so they could be confident it wouldn't have any side effects for the system. So a DSL solution wasn't going to work. But we (the developers) wanted the cron scripts in version control.

So to compromise, we checked text files with the raw cron, similar to this:

10 0 * * * cd /path/to/rails/app && rake RAILS_ENV=production admin:rss

And we added a step to the capistrano script that installed that to the crontab as part of the deploy.

Sarah Mei