Мониторинг планировщика задач Laravel
Планировщик Laravel хранит все периодические задачи в коде за одной строкой в crontab. Эта единственная строка и есть слабое место: если её нет на новом сервере, ничего из расписания не запускается, а Laravel никак не может об этом сообщить. Хорошая новость: планировщик умеет сам отправлять пинги на адрес мониторинга, так что следить за ним можно несколькими строками.
Пинги из каждой задачи
Начиная с Laravel 11 расписание живёт в routes/console.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('backup:run')
->dailyAt('03:17')
->withoutOverlapping()
->pingBefore('https://ping.heartcron.com/<uuid>/start')
->pingOnSuccess('https://ping.heartcron.com/<uuid>')
->pingOnFailure('https://ping.heartcron.com/<uuid>/fail');
В Laravel 10 и раньше та же цепочка пишется в методе schedule() файла app/Console/Kernel.php и начинается с $schedule->command(...).
pingBeforeсообщает о старте, поэтому зависшая задача будет замечена.pingOnSuccessиpingOnFailureсообщают о результате. Laravel считает ошибкой ненулевой код выхода Artisan-команды или shell-команды, поэтому лучше всего они работают с задачамиcommand()иexec().- Методы пингов используют Guzzle, который уже есть в новых приложениях Laravel.
Не храните адреса в коде и отправляйте пинги только с продакшена:
// config/services.php 'heartcron' => [ 'backup' => env('HEARTCRON_BACKUP_URL'), ], // routes/console.php $url = config('services.heartcron.backup'); Schedule::command('backup:run') ->dailyAt('03:17') ->environments(['production']) ->pingBefore("$url/start") ->pingOnSuccess($url) ->pingOnFailure("$url/fail");
Следите за самим планировщиком
Все задачи по расписанию зависят от этой строки в crontab:
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
Если она пропадёт, проверки отдельных задач со временем сработают, но еженедельная задача промолчит неделю. Добавьте «пульс» — задачу, которая каждые пять минут только отправляет пинг:
Schedule::call(fn () => null)
->everyFiveMinutes()
->name('heartbeat')
->thenPing(config('services.heartcron.scheduler'));
Создайте для неё проверку с периодом 5 минут и запасом 5 минут. Если строка из crontab исчезнет или сервер остановится, вы узнаете об этом в течение десяти минут.
Несколько серверов
Если приложение работает на нескольких серверах, добавьте ->onOneServer() к задачам, которые должны выполняться один раз. Для этого нужен общий для всех серверов драйвер кеша, например Redis или база данных. Пинг придёт с того сервера, который выполнил задачу, и проверка увидит ровно один запуск.
В контейнерах
Вместо cron запускайте php artisan schedule:work как основной процесс отдельного контейнера: он выполняет планировщик каждую минуту на переднем плане. Задача-«пульс» выше сообщит, когда этот контейнер остановится.