Skip to content
Get started

How to monitor the Laravel scheduler

The Laravel scheduler runs every task from a single system cron entry that calls schedule:run every minute, so if that one cron stops, every scheduled task stops silently. To monitor it, use the scheduler's built-in pingOnSuccess and pingOnFailure hooks to send a heartbeat to an external monitor, and alert when the expected ping doesn't arrive. Confirm first that the underlying * * * * * cron entry actually exists on the server.

Why did my Laravel scheduled task stop running?

Laravel's scheduler is driven by a single crontab line that runs the artisan scheduler every minute. If that line is missing, the queue worker is down, or the server was reprovisioned without it, none of your scheduled tasks run and Laravel logs nothing about it.

crontab -e (on the server)
* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1

Confirm that line is present with `crontab -l`. If it's gone, that single missing entry explains every task that stopped.

How do I get alerted when a Laravel task is missed?

The scheduler has built-in hooks for exactly this. Chain pingOnSuccess (or thenPing) onto a scheduled task to hit a monitor URL when it finishes, and pingOnFailure to hit a different URL when it errors. Define the schedule in routes/console.php on Laravel 11+ (or the Kernel's schedule() method on Laravel 10 and earlier):

routes/console.php (Laravel 11+)
use Illuminate\Support\Facades\Schedule;

Schedule::command('reports:send')
    ->dailyAt('03:00')
    ->pingOnSuccess('https://ping.cronshield.com/<your-check-id>')
    ->pingOnFailure('https://ping.cronshield.com/<your-check-id>?fail=1');
app/Console/Kernel.php (Laravel 10 and earlier)
protected function schedule(Schedule $schedule): void
{
    $schedule->command('reports:send')
        ->dailyAt('03:00')
        ->pingOnSuccess('https://ping.cronshield.com/<your-check-id>')
        ->pingOnFailure('https://ping.cronshield.com/<your-check-id>?fail=1');
}
The ping URLs are placeholders for the check-specific endpoint you'll get when you create a monitor. The CronShield receiver ships in an upcoming release; the pingOnSuccess/pingOnFailure pattern is stable Laravel today.

What if the whole scheduler stops, not just one task?

Per-task pings tell you a specific task stopped, but if the * * * * * cron itself dies, no pings fire at all — which the monitor reads as a miss and alerts on. That's the case you most want covered, because a dead schedule:run takes down everything at once. Set the monitor's expected period to match each task's schedule so a stalled scheduler surfaces fast.

On paid tiers, CronShield reads the failing task's output and adds the last log line and a likely cause to the alert, so a failure that pinged pingOnFailure comes with context instead of just a red flag.

Add a missed-run alert to this job

The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.

Frequently asked questions

What's the difference between pingOnSuccess and thenPing in Laravel?
pingOnSuccess fires only when the task succeeds; pingOnFailure fires only on failure. thenPing fires after the task regardless of outcome. For missed-run monitoring, pingOnSuccess is what you want so a failure withholds the ping and triggers the alert.
Does the Laravel scheduler retry a task that failed?
No, not by default. A scheduled command runs once at its due time. If it fails, it won't rerun until the next scheduled slot — another reason to be alerted on failure rather than waiting for the next window.