Laravel Command Schedule Not Working Properly

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Troubleshooting Laravel Command Schedule: Why schedule:run Only Runs Once

As a senior developer working with Laravel, setting up scheduled tasks is a critical feature for maintaining automated processes. When you define a schedule using the schedule() method, the expectation is that these tasks will run automatically and repeatedly in the background, much like a system cron job.

However, based on your description—where running php artisan schedule:run only executes the command once—you are encountering a very common misunderstanding regarding how Laravel's scheduler interacts with the operating system environment. This post will diagnose why this happens and provide the correct, robust solution for ensuring your commands execute hourly or minute-by-minute reliably.

Understanding the Misconception: Scheduler vs. Execution

The core issue lies in the difference between defining a schedule and executing that schedule.

When you define tasks using Schedule::command('pdf:update')->everyMinute(), you are merely telling Laravel what jobs should be run based on the current time, provided an external mechanism is polling for them.

The command php artisan schedule:run is designed to check the defined schedule and execute any pending jobs at that exact moment within your CLI session. It is not a persistent background service. If you run it manually, it checks the schedule once and exits. It does not establish a continuous loop like a true cron daemon does on a server.

For scheduled tasks to work continuously in the background—especially for recurring hourly or minute-by-minute updates—they must be managed by an external system that executes the Artisan command periodically, such as a Linux cron job.

The Correct Approach: Leveraging System Cron Jobs

The most reliable and standard way to handle scheduled tasks in a production environment (or even reliably on localhost for sustained operation) is by using the operating system’s built-in scheduler, Cron.

Instead of relying on manually running php artisan schedule:run every minute, you should configure your server's cron table to execute this command repeatedly.

Step 1: Ensure Your Command and Schedule are Correct

First, let's review the code you provided. The setup for defining the command and scheduling it looks structurally correct within Laravel conventions.

Command Definition (app/Console/Commands/PDF.php):
Your command correctly defines the action to be performed.

php
// Example snippet from your PDF command
public function handle()
{
    $event = new Event();
    $event->user_id = 1;
    $event->save();

    echo 'done';
}

Kernel Scheduling (app/Console/Kernel.php):
Your schedule definition correctly maps the command to run every minute:

php
protected function schedule(Schedule $schedule)
{
    $schedule->command('pdf:update')->everyMinute();
}

Step 2: Setting Up the System Cron Job

To make this schedule persistent, you need to tell your server (or localhost environment) to execute php artisan schedule:run every minute.

  1. Determine the Full Path: Find the full path to your Laravel executable.

    bash
    which php
    # Example output: /usr/bin/php
  2. Edit Crontab: Open your crontab file for editing (usually by running crontab -e).

  3. Add the Schedule Entry: Add a line that runs the scheduler command every minute (* * * * *):

    cron
    * * * * * /usr/bin/php /path/to/your/project/artisan schedule:run >> /dev/null 2>&1

    Replace /usr/bin/php and /path/to/your/project/artisan with your actual paths.

This setup ensures that every minute, the operating system forces Laravel to check the schedule and execute any pending jobs defined in your Kernel.php. This is how you achieve true background scheduling, which aligns with best practices for robust application management, as promoted by the principles found on https://laravelcompany.com.

Conclusion

The failure point was not in your command or schedule definition, but in the execution method. Laravel's scheduler is a framework tool; it requires an external operating system mechanism (like Cron) to act as the persistent clock that triggers those tools regularly. By moving the responsibility of execution to cron, you ensure that your hourly PDF updates run reliably every minute without requiring continuous manual intervention or reliance on ephemeral CLI sessions. For any serious application development, mastering this interaction between the application layer and the operating system is fundamental.