Laravel scheduler monitoring matters because scheduled tasks often fail quietly. Your app can be online, your homepage can return 200 OK, and your dashboard can look fine โ while invoices are not generated, reminders are not sent, cleanup jobs are not running, or subscription syncs are stuck.
The tricky part is that Laravel scheduled tasks usually run behind the scenes. If nobody checks whether they completed, failures can stay invisible for days.
The problem
Most Laravel apps use one system cron entry:
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
Then scheduled tasks are defined in Laravel:
protected function schedule(Schedule $schedule): void
{
$schedule->command('reports:send')->dailyAt('08:00');
$schedule->command('subscriptions:sync')->hourly();
$schedule->command('cleanup:old-sessions')->everyThirtyMinutes();
}
That setup is clean, but it creates a blind spot.
If cron stops calling schedule:run, none of those tasks run. If a command fails under cron because of permissions, paths, environment variables, or PHP version differences, the main app can still work normally.
Uptime does not prove scheduled tasks are running.
Why it happens
Laravel scheduler failures usually come from a few practical causes:
- The system cron entry is missing or disabled.
- Cron runs from the wrong directory.
- The PHP binary differs between shell and cron.
- Environment variables are missing.
- Deployments change paths or symlinks.
- A task hangs or overlaps.
- A command catches errors without alerting anyone.
A task can also start successfully but fail before doing the work that matters. That is why Laravel scheduler monitoring should care about successful completion, not only process start.
Why it's dangerous
Missed scheduled tasks often create delayed damage.
A failed billing job can delay revenue. A missed cleanup task can slowly fill storage. A broken reminder job can reduce activation. A stale sync can leave users with wrong data.
These failures are dangerous because they are quiet. By the time someone notices, you may need to reconstruct several days of missing work.
How to detect it
A simple solution is heartbeat monitoring.
A heartbeat is an HTTP request sent by your scheduled task after it completes successfully. A monitor expects that ping within a defined time window. If the ping does not arrive, you get an alert.
For Laravel scheduler monitoring, you can monitor:
- The global scheduler.
- Individual important commands.
- Successful completion of critical jobs.
- Different schedules with separate heartbeat URLs.
For important work, per-command monitoring is usually better than one generic scheduler check.
Simple solution (with example)
Suppose you have this scheduled command:
$schedule->command('subscriptions:sync')
->hourly()
->withoutOverlapping();
Inside the command, send a heartbeat after the sync succeeds:
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
class SyncSubscriptions extends Command
{
protected $signature = 'subscriptions:sync';
public function handle(): int
{
$this->syncSubscriptions();
Http::timeout(5)->get('https://quietpulse.xyz/ping/YOUR_TOKEN');
return self::SUCCESS;
}
}
The placement matters. If you send the heartbeat before the sync, you only prove the command started. Sending it after the work proves the command reached successful completion.
A cleaner version keeps the URL in config:
$pingUrl = config('services.scheduler_pings.subscriptions_sync');
if ($pingUrl) {
Http::timeout(5)->get($pingUrl);
}
In config/services.php:
'scheduler_pings' => [
'subscriptions_sync' => env('SUBSCRIPTIONS_SYNC_PING_URL'),
],
In .env:
SUBSCRIPTIONS_SYNC_PING_URL=https://quietpulse.xyz/ping/YOUR_TOKEN
This keeps monitor URLs out of source code and lets each environment use its own value.
Common mistakes
1. Monitoring only uptime
HTTP uptime checks do not tell you whether scheduled tasks completed. Your Laravel app can be online while the scheduler is broken.
2. Sending the heartbeat too early
If you ping at the start of a command, the monitor may report success even if the task fails later.
Better:
public function handle(): int
{
$this->processInvoices();
Http::get('https://quietpulse.xyz/ping/YOUR_TOKEN');
return self::SUCCESS;
}
3. Using one monitor for every scheduled task
A single global heartbeat is better than nothing, but it can hide failures in individual jobs. Critical tasks deserve separate monitors.
4. Forgetting about stuck overlaps
withoutOverlapping() is useful, but stuck locks can prevent future runs. A missing heartbeat helps reveal that something stopped completing.
5. Depending only on logs
Logs help with debugging, but they are not always a reliable alerting system. A missing heartbeat is a clearer signal.
Alternative approaches
Laravel gives you scheduler output options:
$schedule->command('reports:send')
->daily()
->sendOutputTo(storage_path('logs/reports.log'));
You can also email output on failure:
$schedule->command('reports:send')
->daily()
->emailOutputOnFailure('ops@example.com');
These are useful, but they do not always catch tasks that never started.
Error tracking tools can catch exceptions. Queue dashboards can show background worker health. Database audit rows can record successful runs.
But heartbeat monitoring answers a specific question directly:
Did this scheduled task report success within its expected window?
That is the question most teams actually need answered.
FAQ
What is Laravel scheduler monitoring?
Laravel scheduler monitoring is the practice of checking whether scheduled Laravel commands run and complete when expected.
Is uptime monitoring enough?
No. Uptime monitoring checks your web app, not your scheduled tasks.
Should I monitor every Laravel command?
Not necessarily. Start with critical jobs: billing, imports, reports, cleanup, reminders, and anything that affects users or money.
Where should the heartbeat go?
Usually after the important work completes successfully.
Conclusion
Laravelโs scheduler is convenient, but scheduled work can fail silently. The safest pattern is to monitor important commands directly.
Add a heartbeat after successful completion. If the heartbeat goes missing, you know the task did not complete on time โ before users notice the consequences.
Originally published at https://quietpulse.xyz/blog/laravel-scheduler-monitoring
Top comments (0)