Laravel 5 Cron Jobs on shared hosting

Reading time ~2 minutes

Introduction

The Laravel documentation covers all the information you need to configure Cron Jobs on your hosting machine. Some years ago we were required to define an entry on the server for each task we needed to schedule. Now with Laravel we can simply define a single entry that interacts with the Schedule object, which will take care to run the tasks that are due.

The only Cron entry needed on the server, is the following

* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1

Basically it means that every minute (* * * * *) php will run the artisan command schedule:run. The notation >> /dev/null 2>&1 basically means that the standard output (STDOUT) is redirected to /dev/null and so it is ignored, while 2>&1 means that STDERR is redirected to STDOUT1.

Define Jobs

In the schedule method of the App\Console\Kernel class you can define the tasks you are planning to execute, using a Closure.

$schedule->call(function () {
    // ... your code
})->daily();

The frequency of these tasks is defined by a variety of handy methods that Laravel provides, or you can simply use cron('* * * * *'), if you are more familiar with the Cron notation.

Moreover the Schedule class lets you schedule also Artisan commands

command('artisan:command')

or operating system commands

exec('')

The Problem

Frequently on cheap shared hostings you have not so much space for customization. In most of the cases these hosting providers doesn’t provide SSH access to their servers, instead they will only let you define tasks through the control panel. Sometimes you can’t even manually define a crontab entry, because the hosting allows you only to schedule URL calls. In these cases remember that you can always call Artisan commands via code, from a route or controller, using the Artisan facade:

Route::get('/foo', function () {
    $exitCode = Artisan::call('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);
});

Recently I stumbled upon a hosting provider which allows the use of manual crontab entries in the control panel, however every scheduled tasks configured in the Schedule class was failing with a strange message:

'ErrorException' with message 'Invalid argument supplied for foreach()' in /home/project/vendor/symfony/console/Input/ArgvInput.php

My code was really straightforward

$schedule->command('newsletter:send')->daily();

After some googling turned out that the ini directive register_argc_argv was disabled on the php.ini and I needed to enable it explicitly on each call in order to accept argc and argv parameters. Luckily I easily solved this problem using exec instead of command

$schedule->exec('php -d register_argc_argv=On /path/to/artisan newsletter:send')

Using exec however you don’t have access to emailOutputTo and sendOutputTo, which are exclusive to the command method.

  1. Where not explicitly defined, STDIN, STDOUT and STDERR are numbered with 0, 1, and 2, in that order.