CronPup

← Guides

Monitoring the Laravel scheduler and scheduled commands

Laravel's scheduler depends on one system cron entry that runs php artisan schedule:run every minute. If that entry disappears (new server, container rebuild, a deploy that skipped it), every scheduled task silently stops. Individual commands can also fail without anyone noticing.

1. Monitor the scheduler itself

Add a heartbeat task that runs every minute. If the scheduler stops, this monitor goes down within minutes:

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

Schedule::call(fn () => null)
    ->everyMinute()
    ->name('scheduler-heartbeat')
    ->thenPing('https://cronpup.com/p/SCHEDULER-UUID');

In CronPup, set this monitor to "every 1 minute" with a 5-minute grace period.

2. Monitor important commands

Laravel's built-in ping hooks report success and failure separately:

Schedule::command('backup:run')
    ->dailyAt('03:00')
    ->timezone('Europe/Berlin')
    ->pingBefore('https://cronpup.com/p/BACKUP-UUID/start')
    ->pingOnSuccess('https://cronpup.com/p/BACKUP-UUID')
    ->pingOnFailure('https://cronpup.com/p/BACKUP-UUID/fail');

Set the CronPup monitor's schedule to the cron expression 0 3 * * * with timezone Europe/Berlin, so it expects the run at exactly the same time. The ping methods need the Guzzle HTTP library, which new Laravel projects include by default (composer require guzzlehttp/guzzle otherwise).

Keep URLs out of code

Put the ping URLs in .env and read them via config(), so staging doesn't ping production monitors.

Monitor your Laravel schedule. 10 monitors are free.