Laravel Cron: The Definitive Guide

  • Laravel Cron: The Definitive Guide

    Sharing is Caring... Show some love :)

    So you wish to automate some tasks in your newly created application with Laravel, say you want to send out birthday day messages, promotional emails or you simply want to optimise and back up your database with Laravel Cron periodically.

    How do you achieve this in your Laravel project?

    To automate this task, a task scheduling system is required and Cron Job seems like a perfect solution to your need, but Cron job itself is complicated and required strong domain knowledge to be able to set it up properly.

    The solution is:

    Laravel Cron Job offers a seemly, elegant, and easy to learn Task scheduling mechanism that suits exactly our problem.

    So how do we get started?

    In this article, we are going to explore everything you need to know about Cron Jobs, Laravel Cron Jobs, and the Task Scheduling System, we are going to build projects that leverage the Cron Job to demonstrate how it works and how easy it is to set it up in Laravel.

    By the way, if you’re just starting with Laravel, I have created a Complete Laravel Guide just for you.

    Before you dive in, if you’re a backend developer or looking at delving into this career path, join other developers to receive daily articles on backend development that will boost your productivity.

    What is Cron?

    Cron is a time-based task scheduler in Linux/Unix operating systems. It is used to run a shell command in a specific time period repeatedly. For this to work, Cron uses a special configuration file called Crontab or Cron Table to create and manage the Task scheduling process.

    If you’re a fan of Linux, you probably might have heard of Cron Job before, if not, well, now you know.

    The Crontab contains all the specific Cron Jobs with their specific time and commands to execute.

    So you can say that a CronJob is composed of two parts, The expression (Time) and the Command (Task).

    Let’s see an example:

    * * * * * * command/to/run

    The expression part is the (* asterisk) part and the command part is the command/to/run which is the task to be executed at the specified time.

    The 5 asterisks represent different times such as minute, hour, day of the month, month, and day of the week respectively.

    To execute a particular task every five minutes, simply run:

    5 * * * * command/to/run

    Cron Job requires command line knowledge to master, Check Wikipedia for more information. 

    Also, you have to manage and update each Cron Job individually each time. That could easily become tedious because you have to SSH into your server each time you want to update or add a new Cron Job. 

    With Laravel, you don’t even need to master those commands or SSH into your server each time to add or modify existing Cron Job because Laravel Cron Job has simplified the process and provide you with methods to modify and add new Cron Job without SSHing into your server.

    Let’s look at how?’

    What is Laravel Cron?

    Laravel Cron Job offers the best approach to managing and updating your Cron Jobs. It provides a more fluent and easy way to define schedules/Cron jobs within your Laravel application itself without writing any command-line codes or SSHing into your server each time.

    Sounds good? Let’s understand how it works:

    Inside app/Console/Kernel.php file, there is a method called schedule, this is where you may define all your Tasks to be executed periodically.

    Defining Schedules/Jobs

    To demonstrate, we will schedule a Closure function to be called every five minutes, this function will send out emails to Admin every five minutes.

    ALSO READ  Laravel 8 Multiple Role-based authentications

    Open the file at app/Console/Kernel.php and paste in the below code inside the schedule method.

       /**
         * Define the application's command schedule.
         *
         * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
         * @return void
         */
        protected function schedule(Schedule $schedule)
        {
            $schedule->call(function () {
                $this->SendAdminEmail();
            })->everyFiveMinutes();
        }

    Using the call method, we can pass in Closure functions and the period we want our task to be executed, in our example above, we wanted our emails to be sent every five minutes hence everyFiveMinutes().

    Laravel provides many other schedule frequency options like that, you can explore a list of them too. You can even schedule based on many parameters like Timezones, Truth Test Constraints (conditional), Environment Constraints, Day Constraints, and Between Time Constraints.

    Scheduling an Artisan Command

    Assuming you have a favourite artisan command that you run at least once a day on your server, you can schedule a Laravel Cron Job to run that command for you without having to do it yourself.

    Let’s see how?

    My favourite command of all time in Laravel is php artisan optimize:clear to clear out all cached files.

    Let’s see how we can ask Laravel Cron to run this command once a day:

    To run artisan commands, use the command method of the app/Console/Kernel.php file like below.

    
        /**
         * Define the application's command schedule.
         *
         * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
         * @return void
         */
        protected function schedule(Schedule $schedule)
        {
            $schedule->command('php artisan optimize:clear')->daily();
        }
    

    Scheduling a Queued Job

    Assuming you have learned about Laravel Queues and you have created a new queued job to send birthday messages to users whose birthday is due.

    You can use the job method of the app/Console/Kernel.php to schedule such tasks like below.

        /**
         * Define the application's command schedule.
         *
         * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
         * @return void
         */
        protected function schedule(Schedule $schedule)
        {
            $schedule->job(new Birthday()->sendGift())->dailyAt('00:00');
        }

    That will send birthday gifts to users daily at 00:00 hour.

    Other Scheduling Methods

    In the same spirit, you can execute a different script on the server with the exec command like below.

    /**
         * Define the application's command schedule.
         *
         * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
         * @return void
         */
        protected function schedule(Schedule $schedule)
        {
            $schedule->exec('node /home/public_html/scriptToBackUpDatabse.js')->weekly();
        }

    The code above will execute a Node.js script to backup our database every week.

    Executing one task at intervals

    Assuming you want to wait for a Task to finish executing before moving to another task, you can append the ->withoutOverlapping() method to either the call, job or command method of the app/Console/Kernel.php

    Like this:

    
    $schedule->command('emails:send')->daily()->withoutOverlapping();
    
    // Or specifying time
    
    $schedule->command('emails:send')->daily()->withoutOverlapping(20); // wait for 20 minutes

    Multiple Servers

    Also, assuming your application is running on multiple servers, and you want to run your Laravel scheduler only on one server to avoid duplication.

    You can append onOneServer() to the scheduler.

    $schedule->command('generate:reports')->weekly()->onOneServer();

    Background or Maintenance Mode

    You can also run your task in the background or on maintenance mode:

    
    // Running in Background
    $schedule->command('emails:send')->weekly()->runInBackground();
    
    // In maintenance mode
    $schedule->command('emails:send')->evenInMaintenanceMode();

    Scheduling Task Outputs

    Sometimes, when you execute a task, you expect it to return an output so that you store it in a file or database for further analysis.

    You can achieve this with the Laravel Cron task output methods:

    
    // This sends output to the file path specified.
    $schedule->command('emails:send')
             ->daily()
             ->appendOutputTo($filePath);
    
    // This sends output the a file and also sends out email to the address specified
    $schedule->command('report:generate')
             ->daily()
             ->sendOutputTo($filePath)
             ->emailOutputTo('[email protected]');
    
    // This sends failure output to the email address specified
    $schedule->command('report:generate')
             ->daily()
             ->emailOutputOnFailure('[email protected]');

    Note that Task Outputs only work on command and exec methods only.

    You might want to run some code before or after a task is executed, or even when a task is executed successfully or failed along the way.

    ALSO READ  Laravel One to Many relationships with CRUD example

    Doing all these is really easy with Laravel Cron Job Task Hooks:

    // Before and After hook
    $schedule->command('emails:send')
             ->daily()
             ->before(function () {
                 // The task is about to execute...
              $this->updateStatusToSending();
             })
             ->after(function () {
                 // The task has executed...
                $this->updateStatusToSent();
             });
    
    // On success or failure hook
    $schedule->command('emails:send')
             ->daily()
             ->onSuccess(function () {
                 // The task succeeded...
              $this->informAdmin('Email Sent successfully')
             })
             ->onFailure(function () {
                 // The task failed...
              $this->informAdmin('Email sending failed');
             });

    Take a break and subscribe to get access to our free Laravel tips that will improve your productivity.

    Creating a new Project

    Create a new Laravel scheduler

    We will create a simple project to demonstrate how Task scheduling with Laravel Cron Job works. We also demonstrate this by creating a new Command file and registering it in the app/Console/Kernel.php file.

    Let’s get started:

    Run the following command to create a new Laravel project, or if you’re a complete beginner get started with Laravel Framework: The Ultimate guide.

    composer create-project --prefer-dist laravel/laravel cron-demo

    As mentioned above, there are different ways you can create Task Scheduling in Laravel:

    By creating a new Artisan Command file or using the app/Console/Kernel.php file created already which we have demonstrated above.

    Create a new Artisan Command

    To create a new artisan command that will be used as our Laravel scheduler, run the following command.

    php artisan make:command myScheduler

    After running the command, you will be presented with the following codes in app/Console/myScheduler.php.

    <?php
     
    namespace App\Console\Commands;
     
    use Illuminate\Console\Command;
     
    class myScheduler extends Command
    {
        /**
         * The name and signature of the console command.
         *
         * @var string
         */
        protected $signature = 'command:name';
     
        /**
         * The console command description.
         *
         * @var string
         */
        protected $description = 'Command description';
     
        /**
         * Create a new command instance.
         *
         * @return void
         */
        public function __construct()
        {
            parent::__construct();
        }
     
        /**
         * Execute the console command.
         *
         * @return mixed
         */
        public function handle()
        {
            //
        }
    }

    In our code below, the following line represents the signature of the command which we will be using to call the Laravel scheduler to perform the task.

    protected $signature = 'command:name';
    
    // Replace it with a good name
    
    protected $signature = 'birthday:send';

    Next, we have the Description Property which is used to describe what the command is all about.

    protected $description = 'Command description';
    
    // Replace it with a Descriptive information
    
    protected $description = 'Send a happy birthday message to due users';

    Lastly, we have the handle method which is where our task will be placed. Add the following code to the handle method to send birthday messages.

    
       public function handle()
        {
            $users = User::whereMonth('dob', '=', date('m'))->whereDay('dob', '=', date('d'))->get();
            foreach ($users as $user) {
                Mail::raw('Wishing you a Happy Birthday', function ($mail) use ($user) {
                    $email->to($user->email)
                   $email->from('[email protected]')
                    $email->subject('Happy Birthday to you');
                });
            }
        }

    The above code will just send out a birthday messages to due users.

    Note: Make sure to configure your mail and database parameters correctly.

    Let’s move on to registering the Laravel Scheduler in the Kernel.php so Laravel can recognise and run our Task periodically.

    Registering the scheduler

    Registering our newly created Laravel Scheduler is as simple as adding it to it to the Kernel.php file.

    Go to app/Console/myScheduler.php and add the following codes.

    <?php
    namespace App\Console;
    use Illuminate\Console\Scheduling\Schedule;
    use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
    class Kernel extends ConsoleKernel
    {
        /**
         * The Artisan commands provided by your application.
         *
         * @var array
         */
        protected $commands = [
            Commands\myScheduler::class,
        ];
        /**
         * Define the application's command schedule.
         *
         * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
         * @return void
         */
        protected function schedule(Schedule $schedule)
        {
          $schedule->command('birthday:send')
                ->daily();
        }
        /**
         * Register the commands for the application.
         *
         * @return void
         */
        protected function commands()
        {
            $this->load(__DIR__.'/Commands');
            require base_path('routes/console.php');
        }
    }

    Great!

    ALSO READ  Motivational tips for backend developers

    Now if you run php artisan list command, you should see it listed among the other available commands.

    You can also send birthday messages with simply running an Artisan Command in your terminal.

    php artisan birthday:send

    Also note that you can simply add every thing inside the Kernel.php file instead of creating a new file and registering it. But this way is more elegant and organised than adding everything inside the Kernel.php file.

    Running The Scheduler

    We are going to look at different ways you can execute your Laravel Cron Job or Task schedulers.

    Running the Scheduler locally

    This is the most basic way of running the Laravel scheduler because you don’t need to add any cron tab entry to your local development machine.

    You can simply get your Laravel scheduler running by executing the following command in your project terminal.

    php artisan schedule:work

    Running in Shared Hosting

    To run your Laravel scheduler in a Shared hosting environment, you need to open the Cron Job tab settings and add the following scripts.

    In CPanel, search for Cron Job menu and click to open it. When on the page, choose your time and add your command to execute like below.

    cron 1024x658 - Laravel Cron: The Definitive Guide

    Make sure the change the username appropriately.

    Running with Terminal 

    If you have access to your terminal through SSH, you can simply run the following command to start your scheduler, then you need a service like PM2 to keep it running in the background when you close your terminal on production. 

    Follow the steps below to run your scheduler in your terminal.
    SSH into your production server.

    Change directory to your Laravel project folder.

    Run the following command with it or set up a process manager.

    php artisan schedule:run

    Running in Heroku

    Heroku has the best material for learning how to run Cron Job with Heroku, you can access the material here. Then even offer free 7 days trial to test out your project in production.

    Running with a Cron Service

    One of my favourite way of running Laravel Scheduler is running it as a service on another server.

    Let’s take a look at it:

    Convert your Laravel Scheduler to a route and execute it using cURLs over https://cron-job.org/

    Open your web.php file and add the following code.

    Route::get('send', function(){
      return Artisan::call('birthday:send');
    });

    The code above added a route to call the Birthday Scheduler we created earlier.

    Now, to execute the command, go to https://cron-job.org and register, after that create a new Cron Job and reference the route in the URL input field.

    cronsite 1024x864 - Laravel Cron: The Definitive Guide

    If everything goes well, this will execute your route send every day at 00:00 hour which will in turn execute the Artisan command we specified earlier.

    Conclusion

    That was a long read, i must confess:

    If you’re here, congratulations.

    So far, we have discussed in detail Laravel Cron Jobs and we have listed the different ways we can use Laravel Cron Job or Schedulers, we have also discussed how to create a new Artisan Command file and demonstrated it with a project.

    Lastly we went over running the scheduler where we discuss different ways you can possibly execute your scheduler.

    If you have any questions or suggestions and observations as you read, please feel free to drop them at the comment section below, which will have to improve the article for others.

    Start Learning Backend Dev. Now

    Stop waiting and start learning! Get my 10 tips on teaching yourself backend development.

    Don't worry. I'll never, ever spam you!

    Sharing is caring :)

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99

    Comments

    Newsletter

    Get the latest Backend Dev. jobs, events and curated articles straight to your inbox, once a week

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99
    Top 6 Recent Posts
    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99