Laravel schedule fire only once on initialization

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Laravel Scheduling: How to Ensure Jobs Fire Repeatedly and Reliably

As a senior developer working with the Laravel ecosystem, I frequently encounter situations where scheduled tasks seem to execute only once, even when configured to run repeatedly using methods like ->everyMinute(). This often leads to confusion about how the scheduler interacts with background processing. The issue you are facing—where your shuffleQuoteOfTheDay method fires once but not every minute—is a common misunderstanding of how Laravel's scheduler and queue systems interact.

This post will diagnose why this happens and provide the robust, architectural solution using Laravel Jobs to ensure your tasks execute reliably, every time they are scheduled.

Diagnosing the Scheduling Discrepancy

When you run php artisan schedule:run, Laravel iterates through all jobs defined in your app/Console/Kernel.php file that are due at the current time. If a job is executed successfully, it completes its task. The behavior you describe suggests that while the scheduler registers the call, the actual execution mechanism might be bypassing or terminating prematurely, or perhaps the method itself isn't designed to handle continuous polling efficiently within this specific context.

The core principle in Laravel for handling repetitive, time-based tasks is decoupling the scheduling logic from the execution logic. Relying solely on the scheduler to execute complex operations repeatedly can sometimes lead to race conditions or resource constraints if the task takes longer than expected, leading to the observed single execution.

The Robust Solution: Leveraging Queues and Jobs

The most reliable way to handle repetitive background tasks in Laravel is by utilizing the Queue System. Instead of having the scheduler directly execute complex business logic, we should instruct the scheduler to dispatch a dedicated Job. This shifts the responsibility to the queue workers, which are designed specifically for reliable, repeated execution.

By implementing jobs, you gain several critical advantages:

  1. Decoupling: The scheduling mechanism is separate from the processing mechanism.
  2. Resilience: If a job fails, the queue system allows for automatic retries, ensuring your data integrity (a key concept in building reliable applications, as emphasized by principles found on laravelcompany.com).
  3. Scalability: You can scale your workers independently of the scheduler.

Step-by-Step Implementation

Here is how we restructure your quote shuffling logic into a proper queued job:

1. Create the Job Class

We create a dedicated class that encapsulates the work to be done. This makes the execution unit self-contained and testable.

// app/Jobs/ShuffleQuoteOfTheDay.php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\MotivationalQuote; // Assuming you have this model

class ShuffleQuoteOfTheDay implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @param int $daysAgo
     */
    public function __construct($daysAgo = 1)
    {
        $this->daysAgo = $daysAgo;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // This is where your original logic now lives, safely executed by a worker.
        $randomQuote = MotivationalQuote::where('quote_of_the_day', false)
            ->inRandomOrder()
            ->first();

        if ($randomQuote) {
            $randomQuote->update(['quote_of_the_day' => true]);
        }
    }
}

2. Update the Scheduler Kernel

Now, instead of calling a service method directly in the schedule, we dispatch our new Job.

// app/Console/Kernel.php

protected function schedule(Schedule $schedule)
{
    // Schedule the job to run every minute.
    $schedule->job(new \App\Jobs\ShuffleQuoteOfTheDay())
             ->everyMinute();
}

Conclusion: Building Reliable Systems

By moving your repetitive tasks into dedicated Queued Jobs, you leverage Laravel’s powerful queue infrastructure. The scheduler's role becomes simply dispatching the work, and the queue workers take over the responsibility of reliable execution. This pattern is fundamental to building scalable, fault-tolerant applications. Whenever you are dealing with time-based events or background processing in Laravel, always default to using Jobs rather than attempting to manage complex state directly within the schedule:run command. For deeper insights into managing these systems efficiently, explore the official documentation on laravelcompany.com.