How to Monitor Laravel Cron Jobs with Cronaman
The silent failure problem
Laravel's Task Scheduling is one of the framework's most convenient features. You define all your scheduled tasks in routes/console.php (or the older Kernel.php), add a single crontab entry, and Laravel handles the rest.
The downside: when a scheduled command fails — an exception, a timeout, a misconfigured environment — it logs the error and moves on. There's no built-in mechanism to alert you. Backup commands, invoice generators, and cleanup jobs fail silently for days before anyone notices.
What is heartbeat monitoring?
Heartbeat monitoring gives you an external watchdog. You configure an expected interval in Cronaman, and your command sends a simple HTTP ping after each successful execution. If the ping doesn't arrive within the window, Cronaman alerts you — no polling, no log scraping.
Laravel makes this especially clean: the scheduler's onSuccess and onFailure hooks let you attach the ping directly to any scheduled task without modifying the command itself.
Create a Cronaman monitor
Before touching any code, create a monitor in Cronaman:
- Sign up at cronaman.dev — free plan, no credit card required
- Click New Monitor
- Name it (e.g., "Invoice generator") and set the interval to match your schedule
- Copy your unique ping URL:
https://cronaman.dev/ping/invoice-generator
Using onSuccess and onFailure hooks
Laravel 10+ exposes onSuccess() and onFailure() on every scheduled task. Add your Cronaman pings here — no changes to the command class needed:
use IlluminateSupportFacadesHttp;
use IlluminateSupportFacadesSchedule;
Schedule::command('invoices:generate')
->daily()
->onSuccess(function () {
Http::timeout(10)->get('https://cronaman.dev/ping/invoice-generator');
})
->onFailure(function () {
Http::timeout(10)->get('https://cronaman.dev/ping/invoice-generator/fail');
});Laravel's Http facade (backed by Guzzle) handles the HTTP call. Always set timeout() — Guzzle has no default timeout and will block indefinitely without one.
The older Kernel.php approach
On Laravel 9 or older projects still using app/Console/Kernel.php, the hooks work identically:
use IlluminateSupportFacadesHttp;
protected function schedule(Schedule $schedule): void
{
$schedule->command('invoices:generate')
->daily()
->onSuccess(function () {
Http::timeout(10)->get('https://cronaman.dev/ping/invoice-generator');
})
->onFailure(function () {
Http::timeout(10)->get('https://cronaman.dev/ping/invoice-generator/fail');
});
}Pinging from inside a command
If you prefer to keep the monitoring logic co-located with the command itself, add the ping inside the handle() method:
<?php
namespace AppConsoleCommands;
use IlluminateConsoleCommand;
use IlluminateSupportFacadesHttp;
class GenerateInvoices extends Command
{
const PING_URL = 'https://cronaman.dev/ping/invoice-generator';
const FAIL_URL = 'https://cronaman.dev/ping/invoice-generator/fail';
protected $signature = 'invoices:generate';
protected $description = 'Generate monthly invoices';
public function handle(): int
{
try {
// Your job logic here
$this->generateInvoices();
Http::timeout(10)->get(self::PING_URL); // success
return Command::SUCCESS;
} catch (Throwable $e) {
$this->error("Failed: {$e->getMessage()}");
Http::timeout(10)->get(self::FAIL_URL); // failure
return Command::FAILURE;
}
}
}The single crontab entry
Laravel Task Scheduling only requires one entry in your server's crontab — the scheduler itself decides which tasks run and when:
* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1Set your Cronaman monitor interval to match your command's schedule (e.g., 24 hours for a daily task) and add a 10–15 minute grace period to absorb scheduler startup time and minor clock drift.
Verify your setup
Run the command manually to confirm the ping fires:
php artisan invoices:generateOpen your Cronaman dashboard. Within a few seconds the monitor should show "healthy" with a "Last ping" timestamp. If it stays grey, confirm outbound HTTPS from your server:
curl -v https://cronaman.dev/ping/invoice-generatorMore cron monitoring guides
Using a different stack? The same heartbeat pattern works everywhere:
- How to Monitor Cron Jobs in PHP — covers vanilla PHP file_get_contents and cURL
- How to Monitor Cron Jobs in Python — covers urllib and the requests library
- How to Monitor Cron Jobs in Node.js — covers native fetch, Axios, and node-cron
More guides
What Is Cron Job Monitoring? (And Why You Need It)
5 min readProBeyond Timing: Catch Silent Successes with Semantic Ping Payloads
5 min readPythonHow to Monitor Cron Jobs in Python with Cronaman
6 min readNode.jsHow to Monitor Cron Jobs in Node.js with Cronaman
7 min readPHPHow to Monitor Cron Jobs in PHP with Cronaman
6 min readBashHow to Monitor Cron Jobs in Bash with Cronaman
5 min readRubyHow to Monitor Cron Jobs in Ruby with Cronaman
6 min readGoHow to Monitor Cron Jobs in Go with Cronaman
6 min readStart monitoring your Laravel cron jobs
Free forever for up to 3 monitors. No credit card required. Set up in under 2 minutes.
Start monitoring free