Scheduling tasks in Laravel

On a recent client project I needed to schedule a task so that the site would sync its data with two APIs every day. In the past I would simply have created a CRON job to execute a shell script to execute the update. Laravel makes it so much easier!

It helped that prior to scheduling this task, the client had been executing it manually by clicking a button on the admin panel. This was never meant to be permanent. I had also created a Laravel Console command to execute the update, with various parameters, any time I wanted during the development process. In other words, the code for the task already existed.

This post actually covers four topics, each of them briefly:

  1. Creating a Laravel Console (Artisan) command that can be executed from the shell
  2. Scheduling the execution of that command at a given interval
  3. Testing the schedule using Artisan during development
  4. Creating a CRON job to run the Laravel schedule

Creating a Laravel Console Command

While it’s possible to schedule the execution of shell scripts using the Laravel scheduler, I’m focusing here on using Laravel console commands. In this case, the command I created was fn:update. The purpose of the command was to make API calls to find new records from one, and to grab metadata for those records from the other. The possible signatures for this command would be:

    php artisan fn:update

    php artisan fn:update --num=50

In other words, do a full update or, optionally, do an update retrieving a max num of records.

Start by creating command. The following statement will create the file SystemUpdate.php in the App\Console\Commands folder

php artisan make:command SystemUpdate

Now, edit the file, and add the signature you want to use, and a description for the Artisan help screen:

protected $signature = 'fn:update {--num=5}';

protected $description = 'Update the FN Index and Metadata';

Note the option added to the end of the function. {--num=5}. This states that the command may be called with an optional flag, in this case a flag accepting a value, the default value of which will be 5 if the user does not use the flag.

Below, in the handle() method, you can add the code that you want to be execute, or call on existing methods you’ve created in other classes, which is what I did in this case. Note the Artisan('down') and Artisan('up') commands in the script that put the system into maintenance mode as the command runs, necessary in this case because the API calls and data processing could take as much as 30 seconds. Note the output at the end of the method: a line we will log when the schedule is run.

 public function handle()
{
    // Your code here
    \Artisan('down');
    $result = \App\Models\Fn\UpdateIndex($num)
    \Artisan('up');
    echo now() . " -- Index updated.  Records imported: {$result->imported}.  Record updated:  {$result->updated}.\n"

}

Schedule the command to run

In this case, I wanted the fn:update command to run once a day. Laravel provides a very easy way to implement this. Simply edit the app/Console/Kernel.pph class, and add the task to the schedule() method. Optionally, you can add some code to log the output. By default, output of the command will be sent to /dev/null and will not be logged.

 $schedule->command('fn:update')->daily()
            ->appendOutputTo(storage_path('logs/update.log'));

Test the schedule

You don’t have to wait and watch until the schedule runs to make sure it’s running properly. You can use Artisan to ensure it will run correctly now.

php artisan schedule:test

Select the command from the list of commands (if you have more than one). The command will be executed immediately, regardless of its sechedule. Check the output to the log file and make adjustments as necessary to get a meaningful log entry.

Create a CRON job to run the Laravel scheduler

This is the only bit of system work you need to do. The Laravel scheduler should be scheduled to be run periodically. This will cause the scheduler to check the list of jobs to be run, and to run those jobs that are scheduled. The Laravel docs suggest a CRON job that will run every minute, ensuring that any tasks you schedule, at any time, will be run when they are meant to be run.

On any *nix system, you can add to your CRONTAB file by running the following commands from terminal. The first will list any CRON jobs you have already schedule. The second, will open an editor so you can add the new job.


crontab -l crontab -e

The Laravel docs suggest adding the following entry, to run the scheduler every minute:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Of course, you probably don’t want to add the schedule to your dev box or desktop machine, but Laravel gives you an easy way to test scheduling using Artisan. This will cause the scheduler to work, in the foreground, until you kill it. Tasks will run whenever they are scheduled to run.

php artisan schedule:work

Conclusion

And that’s it! Scheduling tasks is easy with Laravel. There are many more options I have not discussed here, but the Laravel documentation is clear. The following links may assist.