Scheduling crontabs in Drupal

One of the neat things about the Drupal CMS is that it has a facility to schedule certain things to be run at regular intervals. For example: sending out subscription notifications or indexing posts for the search function. Those operations can take tens of seconds to complete, so you obviously don't want them executing in the middle of a page load.

The normal way to execute Drupal's crontabs is to load the script cron.php via the web interface. This is a terrible idea, since anyone with an Internet connection could cause your machine to run CPU intensive tasks at well, and bring the webserver to its knees.

An alternative way to run crontabs is with a third-party module called Poormanscron. It's a nice module, but the locking facility it has isn't so hot, and on more than one occasion I've had two cron runs execute in parallel, causing extra load on the machine. In especially bad (read: I/O bound) situations, multiple crontabs get "backed up" onto each other, and that creates huge load spikes and 60-second+ page loads until things calm down again.

There is yet a third way to run Drupal crontabs, and that's via the command line. It gives you maximum control over when and where crontabs run, and this is particularly important when you have multiple Drupal sites running. And I'm going to show you how to do it.

Step 1) Download Drush, the Drupal shell. It's a great little app for accessing your Drupal installation and performing common tasks from the command line. Install Drush (I usually put it in /usr/local/drush/, and make a symlink from /usr/local/bin/drush)

Step 2) Create a script in your home directory, and call it drupal-crontabs.sh. It should look something like this:

#!/bin/sh
#
# Our main directory for holding websites
#
ROOT=/var/www

export DRUSH_OPTIONS="-q"
#export DRUSH_OPTIONS="-v" # Debugging

#
# Errors are fatal
#
set -e

cd $ROOT

#
# All of our drupal installations under $ROOT
#
SITES="furryconnectionnorth.com"
SITES="$SITES saveardmorecoalition.org"
SITES="$SITES claws-and-paws.com"
SITES="$SITES sabanews.org"

#
# Loop through our sites to run crontabs on
#
for SITE in $SITES
do
   cd $SITE
   #
   # Disable errors, since sometimes crontabs have issues.
   #
   set +e
   drush $DRUSH_OPTIONS cron
   set -e
   cd ..
done

Be sure to season the $ROOT and $SITES variables to taste as per your specific installation.

If you run a chmod 755 on this script, you can execute it from the command line. However, you may run into file permission issues if the webserver is running as a different user than you (usually the case).

Step 3) Now you need to set up a crontab to run this script. My preferred way to do it is to create a file called /etc/cron.d/drupal-crontabs and place the following in it:

#
# Run all of our crontabs for Drupal once an hour
#
MAILTO=root
PATH=/usr/bin:/bin:/usr/local/bin

15 * * * *     www-data /path/to/drupal-crontabs.sh

Make sure you are running these crontabs under the same user as your webserver.

That's it! If you want to see emailed notifications once an hour, just uncomment the line with the "-v" option for Drush. Otherwise, crontabs on all your sites will be run once an hour. Provided they do not take longer than hour to run, all of your search indexes and subscriptions will be kept up to date, and you will no longer have to worry about crontabs stomping over top of each other with Poormanscron. Enjoy!

1.8
Average: 1.8 (5 votes)
Your rating: None