---
title: "Laravel scheduler monitoring | Logdash"
description: "Why pingOnSuccess falls short, a 10-second heartbeat that catches a dead schedule:run and failed tasks, and an honest look at spatie/laravel-schedule-monitor."
url: https://logdash.io/cron-monitoring/laravel-scheduler
---

# Laravel scheduler monitoring

Add a 10-second heartbeat task that posts to an external monitor only while your job last succeeded within a set window, so one alert covers both a failed task and a scheduler that is not running at all.

The Laravel scheduler fails in two ways. A task exits non-zero, or nothing runs at all: the cron line for schedule:run never made it to the new server, the container running schedule:work was replaced, or someone ran php artisan down and every task skipped. The second is worse: nothing logs a process that never started.

## Laravel cron monitoring with pingOnSuccess

Laravel has pings built in. pingBefore, thenPing, pingOnSuccess and pingOnFailure call a URL around a task, and onSuccess only fires on exit code 0\. There are two catches with Logdash. The scheduler sends those pings as GET, and the Logdash ping route only accepts POST, so they get a 404\. And Logdash push monitors, a Pro feature at $15 a month, are checked every 15 seconds: no ping in that window and the monitor goes down. A daily task cannot keep that up by pinging after itself.

## Laravel scheduler monitoring with a heartbeat

So split it. The real task writes its last success to the cache. A sub-minute task, which the scheduler supports natively, posts to Logdash every 10 seconds while that success is younger than your window.

 routes/console.php 

```php
<?php

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Schedule;

// The task you care about. onSuccess only fires on exit code 0.
Schedule::command('backup:run')
    ->dailyAt('03:00')
    ->runInBackground()
    ->onSuccess(fn () => Cache::forever('backup:ok', now()->timestamp));

// The heartbeat. Stops when the scheduler stops or the backup goes stale.
Schedule::call(function () {
    if (now()->timestamp - Cache::get('backup:ok', 0) < 25 * 3600) {
        Http::timeout(5)->post('https://api.logdash.io/ping/68b4c1f0e3a2d5c7b9f01234');
    }
})->name('logdash-heartbeat')->everyTenSeconds();
```

- schedule:run not running: no heartbeat, alert within 30 seconds. A missing crontab line, a dead schedule:work container, a server stuck after a reboot.
- The backup exits non-zero or hangs: onSuccess never fires, the timestamp ages, and the pings stop 25 hours after the last good run.
- Maintenance mode: scheduled tasks skip, the heartbeat included, so a forgotten php artisan down reaches you too.

Two details matter. Keep runInBackground on long tasks, as the Laravel docs advise for schedules with sub-minute tasks, or a slow backup can delay the heartbeat and trip a false alert. And use a shared, persistent cache store, because the array driver forgets the timestamp between runs. After each deploy, run php artisan schedule:interrupt so the running scheduler picks up the new code.

1. **Create a push monitor** Add a service in Logdash on Pro, set the monitor to push and copy the monitor id from the ping URL. Name it after the task, since the alert shows the name.
2. **Add the two tasks** Paste them into routes/console.php with your window: the task interval plus the lateness you accept. The monitor reads down until the first backup succeeds, which is the truth.
3. **Stop the scheduler** Comment out the schedule:run cron line or stop the schedule:work process. Within 30 seconds a Telegram message lands saying the monitor is down, status code 0, did not receive call for this time range.

## Laravel schedule monitor packages

spatie/laravel-schedule-monitor logs every start, finish and failure of every task to two tables, lists them with schedule-monitor:list, and flags a task as late when it misses its time plus a grace period, 5 minutes by default. It does not send alerts, on purpose: if the scheduler is broken, a scheduled notification would not run either. Alerts come from syncing the schedule to Oh Dear, which starts at 15 euros a month and has no free plan.

### Logdash vs spatie/laravel-schedule-monitor

| Feature               | Logdash                                  | Spatie package with Oh Dear                        |
| --------------------- | ---------------------------------------- | -------------------------------------------------- |
| Tasks covered         | The ones you wire up, one cache key each | Every task after one sync command                  |
| Late and failed runs  | One freshness window per task            | Schedule-aware, grace time per task                |
| Run history           | Up and down history per monitor          | Start, finish, runtime and memory in your database |
| Scheduler not running | Alert within 30 seconds, without Oh Dear | Only through Oh Dear                               |
| Alert channels        | Telegram and webhook                     | Mail, Slack, SMS, webhooks and more                |
| Price                 | Pro, $15 a month                         | Package free, Oh Dear from 15 euros a month        |

### When spatie/laravel-schedule-monitor is the better pick

- You have more than a handful of tasks. One sync and every task is monitored, with no cache keys to keep in step.
- You want runtime and memory per run in your own database, not only up or down.
- You already pay for Oh Dear. The scheduled task check comes with every plan.
- Your tasks run weekdays only or on odd schedules, where one fixed window either misses late runs or alerts every weekend.

### What is the simplest Laravel scheduler monitoring setup? 

A sub-minute heartbeat task that posts to an external monitor while your important task last succeeded within a window. It catches failed tasks and a dead scheduler with about ten lines in routes/console.php.

### Is there a Laravel schedule monitor package? 

spatie/laravel-schedule-monitor records every run and flags late tasks in schedule-monitor:list. It sends no alerts itself; for those it syncs your schedule to Oh Dear, a paid service.

### How do I tell if the Laravel scheduler is not running? 

Something outside the app has to notice the silence. Check that the cron entry for schedule:run exists on the server that is actually live, then add a heartbeat so the next time it stops you hear about it within 30 seconds instead of next week.

### Can I use pingOnSuccess for Laravel cron monitoring with Logdash? 

Not directly. pingOnSuccess sends a GET and the Logdash ping route only takes POST. One ping after a daily task also cannot satisfy a 15-second check window, so use the heartbeat pattern above.

## Keep reading

[All cron monitoring guides](https://logdash.io/cron-monitoring): One guide per scheduler, each with the code that proves a job ran and the alert for when it did not.

[Celery beat monitoring](https://logdash.io/cron-monitoring/celery-beat): Have beat send a canary task every 10 seconds that posts to a Logdash push monitor, and the first 15 seconds without a ping tells you beat, the broker or every worker has stopped.

[Sidekiq monitoring](https://logdash.io/cron-monitoring/sidekiq): The Sidekiq Web UI shows queues, retries and dead jobs while you look at it; to be told when Sidekiq stops processing, run a canary job every 5 seconds that pings a Logdash push monitor.

[BullMQ monitoring](https://logdash.io/cron-monitoring/bullmq): Use Bull Board or Taskforce.sh to see queues and jobs, and add a 10-second job scheduler that pings a Logdash push monitor so you are told when workers stop processing.

[Uptime monitoring](https://logdash.io/features/monitoring): HTTP checks as often as every 15 seconds. When one fails, Telegram tells you before your users do.
