Laravel 13.35 New Published on

Stop a long command cleanly with schedule:interrupt

schedule:interrupt timestamps its signal, and hasBeenInterruptedSince() reads it: a long command stops between two batches, without cutting the current one.

Topics covered: ConsoleScheduling

New in Laravel 13.35. php artisan schedule:interrupt asks scheduled tasks to stop, before a deployment for example. But a command already running, especially in the background (runInBackground()), did not hear it: it went to the end, or got killed in the middle of a batch.

Since Laravel 13.35

The interruption is now timestamped, and Schedule::hasBeenInterruptedSince() tells whether it happened since a given moment. A long command checks it at a point where stopping breaks nothing:

use Illuminate\Console\Scheduling\Schedule;

public function handle(Schedule $schedule)
{
    $start = now();

    foreach ($this->batches() as $batch) {
        if ($schedule->hasBeenInterruptedSince($start)) {
            return;
        }

        $this->process($batch);
    }
}

Comparing with the start time, and not with "an interruption exists", matters: the signal of yesterday's deployment stays in the cache, and must not block the next runs.

Your task

The reminders:send command sends reminders for unpaid invoices every night, in batches of ten. A batch that has started must finish: stopped in the middle, it would remind some customers twice.

Make it stop between two batches when schedule:interrupt has been run since it started. The remaining invoices will go on the next run.

Where the feature comes from: the original pull request.