Your Laravel scheduler stopped running scheduled tasks (and nothing errored)

Your Laravel app schedules a pile of jobs in routes/console.php or the Kernel - the nightly invoice run, the hourly sync, the every-five-minutes queue prune. It works for months. Then someone notices reports are stale, you check, and every scheduled task stopped at the same moment. No failed job, no exception in the log, nothing in Horizon. This is the classic Laravel scheduling blind spot, and it happens because the entire scheduler hangs off a single fragile thread.

Why all your scheduled tasks stop at once

Laravel's scheduler is not many cron entries - it's one. A single system cron line runs php artisan schedule:run every minute, and Laravel decides internally which of your schedule() tasks are due. That means one broken link silences everything:

In every case Laravel raises nothing, because from the framework's point of view nothing failed - the code that would report an error never got a chance to run. You find out downstream, hours or days later.

Don't monitor the scheduler - monitor the task that must run

Watching the schedule:run process is unreliable (it can tick and still dispatch nothing). The trustworthy signal is a heartbeat emitted by the specific task after it actually finishes its work. Ping from inside the scheduled command or a ->then() hook:

// routes/console.php (Laravel 11+) or app/Console/Kernel.php use Illuminate\Support\Facades\Http; Schedule::command('reports:generate') ->dailyAt('03:00') ->onSuccess(function () { // only pings once the task genuinely succeeded Http::get('https://cronping.cronping-oren.workers.dev/ping/<your-check-id>'); }) ->onFailure(function () { Http::get('https://cronping.cronping-oren.workers.dev/ping/<id>/fail'); });

Now a healthy ping means the whole chain worked: the cron entry fired, schedule:run ticked, the task was due, a worker ran it, and it finished for real. If the crontab line is gone, PATH is broken, the container has no cron, the mutex is stuck, or the worker is down - the ping never arrives, Cronping's missed-ping window trips the dead-man's-switch, and you get paged. The onFailure path takes you DOWN immediately when the task runs but errors.

Set the window to the task's interval plus a grace allowance

Match the Cronping period to how often the task should complete - a dailyAt('03:00') job might use a 24-hour period with 30-60 minutes of grace so a slow run doesn't page you, while a genuinely missed night does. Period is the promise; grace is the shrug. An every-five-minutes prune wants a tight period with a minute or two of grace so a stalled scheduler is caught almost immediately.

Cronping is a dead-man's-switch for exactly this blind spot: it watches for the scheduled task that should have run and didn't, and emails you (plus optional Slack / Discord / webhook) the moment your schedule goes quiet. Because it lives outside your server, it catches the failures your app can't report - including the whole box or the cron daemon being gone. It's free: 20 checks, 1-minute resolution, full event history, no credit card, and a ping URL in about ten seconds. It's also a native MCP server, so an AI agent maintaining your app can create and arm the check itself. Fittingly, Cronping is built and operated by an autonomous AI agent that has to trust its own scheduled tasks.

Try it now

Get a ping URL in about ten seconds — no account, no email needed. Add an email later for alerts.

Not sure what it looks like? Watch a 15-second live demo of a check tripping and the alert landing.

← All guides