In this post I will try to explain what is a Cron job and show how to use them in Laravel v3 and v4.

Let’s start with the basics. A Cron job is basically a command that is scheduled to execute at some period of time or at a very specific time. What command? Well, it can be any shell command, same commands that you use in your Terminal.

What’s a good use case of a cronjob?

I would say that cleanup(files and/or DB), sending emails or executing time-consuming actions (like operating with cache) are the primary examples of cronjobs in use. For example in my latest app that I have developed on my own in few days in Laravel 3, a file sharing service, I needed to remove all records that are older than two hours and that don’t have any children records. Also I needed to remove files in the uploads folder that are older than a certain time. Cron jobs = Executing tasks at certain time or at a period of time. As far as I know a cronjob can be setup only on Unix based machines. So this will not work on Windows machines or servers.

How does this apply to Laravel applications?

Since a cron job is just some shell command that is run at a certain time, we can run Artisan commands too. In Laravel 3 custom artisan commands are called “Tasks”. To proceed with this tutorial I highly recommend you check out the documentation of Laravel tasks if you are using Laravel 3. If you are using Laravel 4 please refer to this section in the documentation : http://four.laravel.com/docs/commands and also Nettuts+ has an amazing tutorial written by Jason Lewis about Laravel 4 commands : http://net.tutsplus.com/tutorials/php/your-one-stop-guide-to-laravel-commands/

I will be using Laravel 3 for this tutorial but the concepts are pretty much the same for Laravel 4 applications.

For my example I will want to have a cron job that runs every hour to cleanup some records in the DB. Let’s say I have model “Item” and a model “Bucket”. Each bucket has many items, and I would like to remove all buckets that are empty, i.e. do not have any related “Item” in the DB.

To start with, I need to create a Laravel Artisan task and test that it works. Again, I am using Laravel 3 here so this will be different for Laravel 4.

From L3 docs :

To create a task create a new class in your application/tasks directory. The class name should be suffixed with “_Task”, and should at least have a “run” method, like this (tasks/notify.php):

Creating a task class:

class Notify_Task { public function run($arguments) { // Do awesome notifying... } }

Or in our case :

Creating a class “Custodian” for record maintenance:

class Custodian_Task { public function run($arguments) { $buckets = Bucket::all(); $cnt = 0; foreach ( $buckets as $bucket) { if (!$bucket->items) { $bucket->delete(); $cnt++; } } echo $cnt.' Unclaimed Buckets removed'; } }

In this task I selected all buckets, then going through each bucket I delete all buckets that have no model “Item” associated with it.

Now to run this Laravel Artisan command I execute this in the Terminal (need to cd into application’s folder first) :

php artisan custodian

And if I have some buckets that are empty my Terminal output will be something like this:

7 Unclaimed Buckets removed

Simple? You can put anything in that task as you would put in a controller, and you get to use the awesome Eloquent or Fluent models.

Well now let’s say I want this to be a Cron job. On my server I would run the following command :

crontab -e

Which will launch a cron job manager.

Since it is opening Vi editor, you might want to look at how to operate with it: http://www.washington.edu/computing/unix/vi.html

I just type “i” to enter “insert mode” in Vi editor and start creating my cron job schedule.

Here is a cron job that will run the above mentioned Laravel artisan task once an hour :

1 * * * * /usr/bin/php /Users/me/Desktop/WebDev/projects/laravelapp/artisan custodian

Note that I referenced my laravel project and PHP by giving a full path.

After you are done typing your cron job press Escape, then “:w”, Enter, then “:q” to save your cron job and exit. Now if you run cronjob -l you should see what you typed in the cron job manager and that will mean that the cron job is ready to go and will run once an hour. I have seen instances where cron job would not run and a way to solve that can be as simple as adding a new line at the end of the cron job file. Also make sure that your command runs Ok before you put it in the cron tab. For example I ran this in the terminal to test that the command works:

/usr/bin/php /Users/me/Desktop/WebDev/projects/laravelapp/artisan custodian

And it gave me the desired output so I know that my command works.

What if you want the cronjob to run at a desired time? Well you need to know how the cron schedule works. The format of cron schedule is like this :

minute hour day month day-of-the-week command-to-run

Where :

minute (0-59)

hour (0-23)

day of month (1-31)

month (1-12)

day of the week (0-6 starting on Sunday-0)

Each time entity can be replaced by an asterisk and that would mean to run the cron job at every minute or hour or day of month or month or day of week).

Examples :

Every hour on the 18-th minute of the hour

18 * * * *

Every hour on the 18-th minute of the hour on Tuesdays only

18 * * * 2

You can also run the cron job at an interval of time, let’s say every 15 minutes. For that you need to give this format (asterisk divide by number):

*/15 * * * *

Examples :

Run every other hour at the top of the hour (minute 0)

0 */2 * * *

Every 20 minutes of every other hour

*/20 */2 * * *

You can use this visual cron tab scheduler to easily create the needed time periods:

http://www.corntab.com/pages/crontab-gui

You can email the results of the cronjob to yourself by putting this at the top of the cron job file:

MAILTO="youremail@example.com"

And adding this to the end of your cron job :

> /dev/null 2>&1

That is all there is to it to start using cron jobs in Laravel applications. What are good examples of using Cron jobs in your applications?

Note on optimization : in the Custodian example above my query is very inefficient, imagine my buckets table grows to a million records, this would put a lot of strain on the server. Instead of selecting all items I advise to rely on created_at timestamp of the record (make sure you have proper timezone set in application.php config file in your Laravel app) and select all records older than certain time period. I use Jason Lewis’ Expressive Date package to have full control of what period of time I want to select and that way my records are efficiently selected for example only for the past two hours or past week instead of selecting all records in the DB.

Enjoy using Cron jobs!

Resources on Cronjobs :