How to setup cronjobs for a Laravel project
Tags: webdev, linux, laravel, php
Published: 2022-06-06 17:23:58

Tasks like sending email reminders, checking for inactive users, running daily backups, etc., are usually repetitive and as such developers/sysadmins need to leverage the power of cron to automate such tasks.

 This tutorial will show how to automate tasks in a laravel application (known as scheduling).

In this tutorial, I will be writing a cron job which deletes expired personal access tokens generated by sanctum for authentication from the database after a determined number of days.

**Step 1:** On the command line in the root directory of your Laravel application, run the following command on the console to create a new command: 
`php artisan make:command DeleteExpiredTokens --command=tokens:cron`

**Step 2:** Open the newly-created Command file and edit the logic as follows:
(Directory: **app/Console/Commands/DeleteExpiredTokens.php**)

```

namespace App\Console\Commands;

use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Laravel\Sanctum\Sanctum;
use App\Models\Tokens;
use DateTime;

class DeleteExpiredTokens extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'tokens:cron';

    /**
     * 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 int
     */
    public function handle()
    {
// Get the current time
$now = Carbon::now();

// Set the time limit for deleting tokens (2 days for this tutorial)
$limit = $now->subDays(2);

// Delete all personal access tokens that were created before the limit
try{
    $delete = DB::table('personal_access_tokens')
    ->where('created_at', '<', $limit)
    ->delete();
}
catch (\Illuminate\Database\QueryException $e)
{
    echo "error deleting!! ".$e;
}

echo "Deleted OK for today... ".date('Y-m-d')." , items deleted == ".$delete."<br>";
    }
}
```

The handle() function is the most important part of the command. Here, you can write whatever database, email sending or database backup logic you want.

**Step 3:** Register the command on the Kernel.php file to handle frequency and when you want the command to run.

(Directory: **app/Console/Kernel.php**)

```
<?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\DeleteExpiredTokens::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('tokens:cron')
                 ->timezone('Africa/Lagos')
                 //->everyMinute()
                // ->everySixHours()
                 ->dailyAt('04:00');
                 ->appendOutputTo('cron.txt');
               

    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}

```

In the schedule method, Laravel offers a variety of options for us to define when we want the command to run. Simply define the one that suits your needs. You also can define as many commands as you want and the laravel task scheduler will run all in turn and according to your define timings.
the appendOutputTo() method creates a file that outputs whatever message you returned in the Command file created up in Step 1. This gives instant insight on the whether the cron job is doing what we want.

Further insight is provided in the <a href="https://laravel.com/docs/9.x/scheduling"> official documentation </a>

**Step 4:** In order for our schedules to work, we need to add a single cron entry on the Linux server that will take care of all our schedules from the Laravel application.

Type the following commands on the SSH terminal:
a. `sudo crontab -e`. If this is the first time you are configuring cron on the server, it will prompt for the editor to use.

b. `* * * * * /usr/bin/php /var/www/html/your_laravel_app/artisan schedule:run > /tmp/cron_log.txt`
This is a directive that runs the cron daemon every minute, checks every schedule you defined under Kernel.php, executes it and dump a log file in the tmp folder for analysis. 
Cron will not give information whether or not its commands run successfully, so the only way to troubleshoot is by having a log file.

c. Restart the service by typing: 
`sudo service cron reload`

**Step 5:** You can optionally test-run the schedule locally to simulate how it will run on the server by running:
`php artisan schedule:work`