Cron - Running a script at a set time on a website

August 07, 2014

Reading time ~4 minutes

Timed Event

There's lots of times when building a website that you need something to happen but not from user interaction. As the web is stateless, unless someone is on your site and clicking around, your server side scripts won't run.

The usual reasons I need this to happen:

  • Send out a daily/weekly email report
  • At a set time change the status of content:
    • Set posts/entries to Draft
    • Delete posts/entries
  • Pull in data from somewhere else, like another DB or CMS

It is possible to a 'pretend' timed event. On every page load run a script that checks if a task needs to be done and run it. This is how WordPress wp cron works. A similar approach is used by Automat:ee for ExpressionEngine. If you get a lot of visits to your site then this could be OK.

The drawback is, if you need the task to run at an exact time it's dependant on someone requesting a page at that exact time! Another draw back is the timer is working through a server side language, eg with WordPress it's PHP (same for Drupal, ExpressionEngine, Craft, Perch etc). Every page load will be using a little bit of processing power. If you happen to be the one that triggers the task, and it's complex, you take the hit on the page load.

There is a (better) way to do this via Cron.

Unix Cron

If your website is running on a unix variant (most probably is) there's a built in process to handle any timed tasks, Cron.

Cron is a system daemon used to execute desired tasks (in the background) at designated times.

Although this is handled on the command line, it's very easy to set-up. Cron is always running and goes through any tasks set-up at set times. These tasks are configured in a list, so Cron isn't controlled directly. The list Cron reads is in crontab.

A crontab is a simple text file with a list of commands meant to be run at specified times.

The timings are extensive: every hour, every day, every Monday, every 3rd Friday of the month can all be set-up. Ubuntu has a great write-up on adding tasks to Cron.

Example

Trigger a PHP script to run at midnight every day. The PHP file runs by requesting the 'page' like any normal webpage over HTTP. It makes a call to the database to dump out a backup.

SSH

The first task is to get on to the server. You'll need to have root access and hopefully connect over a secure connection.

$ ssh username@website.com

Enter password.

Cron

Open up crontab to edit:

$ crontab -e

This will put you in the default editor for your shell. On a Mac it's Vim. This will be your users crontab. There's some other things you could worry about, like the global crontab (possibly $ vim /etc/crontab) but the default is probably fine.

Crontab has a task per line in the format:

* * * * * task

Where the asterisks *, configure the time and task of what Cron will do.

All the timing events are in Ubuntu's guide.

In our example we want to 'visit' a link, but first lets set the task to run at midnight everyday.

0 0 * * * task

minute = 0, hour = 0 (midnight) and everything else is a wildcard so is always true. In effect run every day.

Wget

Wget is a terminal command to retrieve files using HTTP, HTTPS and FTP. To do this wget will visit and download a link. We want the first bit, but in this example not the download.

0 0 * * * wget http://www.website.com/backup-script.php

Wget expects to retrieve a file, so we need to tell it to delete whatever it gets back:

0 0 * * * wget -qO- http://www.website.com/backup-script.php &> /dev/null

What do the flags q and O for wget do and what's /dev/null?

Courtesy of Stack Overflow:

Use q flag for quiet mode, and tell wget to output to stdout with O- (uppercase o) and redirect to /dev/null to discard the output: wget -qO- $url &> /dev/null. > redirects application output (to a file). if > is preceded by ampersand, shell redirects all outputs (error and normal) to the file right of >. If you don't specify ampersand, then only normal output is redirected.

And that's it – set a timed script to run using Cron.

Update - mystery emails

After a system update I had a web server mysteriously start sending me emails that Cron had successfully run every day!

Honestly, I have no idea why this happened or how to configure Cron/OS to not email, or only email on error.

After a support call to my host, email notifications can be disabled per Cron task with:

> /dev/null 2>&1

Full explanation on Stack Overflow: http://stackoverflow.com/questions/10508843/what-is-dev-null-21

2>&1 redirects standard error (2) to standard output (1), which then discards it as well since standard output has already been redirected

comments powered by Disqus