- Опубликовано: 19 фев 2025
- 2164
Настройка и отладка расписания (Cron) в Laravel 11 на продакшн-сервере
Настройка и отладка расписания (Cron) в Laravel 11 на продакшн-сервере
Введение
В современных PHP-приложениях часто возникает необходимость выполнять различные задачи по расписанию: обработку очередей, отправку писем, очистку просроченных данных и т.д. Laravel предоставляет удобный способ запуска повторяющихся задач через механизм Task Scheduling.
Однако новичкам иногда бывает сложно разобраться, как правильно настроить cron, особенно при работе в Docker-контейнерах или на собственном сервере (Debian, Ubuntu и пр.). В этой статье мы разберём пошагово:
- Как работает механизм расписания в Laravel 11.
- Как правильно настроить
cron-задачу для Laravel (напрямую в системе и внутри Docker). - Как отлаживать ситуацию, когда
No scheduled commands are ready to run. - Как убедиться, что задачи действительно выполняются.
Шаг 1. Как работает Laravel Scheduler
- Где описываются задачи?
- В большинстве проектов Laravel задачи прописывают в методе
scheduleклассаApp\Console\Kernel. - В новых версиях Laravel (включая 11) есть альтернативный способ конфигурации через файл
bootstrap/app.php(вместоKernel), где можно использовать метод->withSchedule().
- В большинстве проектов Laravel задачи прописывают в методе
- Как запускается расписание?
- Laravel не использует встроенный системный планировщик. Вместо этого вы добавляете задачу (одну!) в системный
cron, которая каждую минуту вызывает командуphp artisan schedule:run. - Когда запускается
schedule:run, Laravel проверяет все ваши задачи и смотрит, пора ли их запускать (с учётом указанных интервалов:daily(),hourly(),everyMinute(), и т.д.).
- Laravel не использует встроенный системный планировщик. Вместо этого вы добавляете задачу (одну!) в системный
- Преимущество такого подхода в том, что вам не нужно прописывать несколько cron-задач в системе. Все задачи (dispatch Jobs, вызовы моделей и т.д.) живут внутри Laravel, а системный
cronтолько «триггерит» их раз в минуту.
Шаг 2. Добавление задачи в расписание
Пример кода (файл bootstrap/app.php):
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use App\Models\Product;
use Illuminate\Support\Carbon;
use Illuminate\Console\Scheduling\Schedule;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// ...
})
->withExceptions(function (Exceptions $exceptions) {
// ...
})
->withSchedule(function (Schedule $schedule) {
// Пример задачи: сбрасываем поле `is_new` у продуктов старше 30 дней
$schedule->call(function () {
Product::where('is_new', 1)
->where('is_new_set_at', '<=', Carbon::now()->subMonth())
->update(['is_new' => 0]);
})->daily(); // Выполнять задачу ежедневно
})
->create();
В этом примере задача будет выполняться раз в сутки, примерно в полночь.
Шаг 3. Настройка системного cron
3.1. На обычном сервере (Debian/Ubuntu и пр.)
- Перейти к пользователю, от имени которого работает веб-сервер (обычно
www-dataна Debian/Ubuntu) и открытьcrontab:sudo crontab -u www-data -e - Добавить строку, которая раз в минуту будет запускать
schedule:run:* * * * * cd /path/to/laravel && /usr/bin/php artisan schedule:run >> /dev/null 2>&1Здесь:* * * * *означает каждую минуту.cd /path/to/laravel— путь к корневой директории вашего проекта./usr/bin/php artisan schedule:run— команда, которая запускает Laravel Scheduler.>> /dev/null 2>&1— подавление вывода команд (чтобы не захламлять логи).
- Сохранить изменения и проверить, что
cronзапущен:sudo systemctl status cron # или sudo systemctl restart cron - Посмотреть, действительно ли
cronсрабатывает, можно в логах системы (Debian/Ubuntu):grep CRON /var/log/syslogЕсли всё верно, вы увидите регулярные записи о запуске.
3.2. В Docker (например, Laravel Sail)
Если ваш Laravel-проект работает внутри контейнера Docker, а не напрямую на хост-системе, нужно учесть нюанс: задача, добавленная в crontab хост-системы, не видит контейнер (или видит с трудом). Поэтому для корректной работы расписания нужно:
- Установить
cronвнутри Docker-контейнера (если его там нет). В случае Laravel Sailcronобычно не установлен по умолчанию. - Добавить нужную строку в
crontabконтейнера. Проще всего это сделать так:
sail shell
crontab -e
И добавить:
* * * * * /usr/bin/php /var/www/html/artisan schedule:run >> /dev/null 2>&1
- Путь к
phpможет отличаться, проверьте командойwhich phpв контейнере. - Путь к проекту (
/var/www/html) может отличаться, смотритеDockerfileилиdocker-compose.yml. Далее нужно перезапустить контейнер:
sail restart
и убедиться, что cron внутри контейнера запущен.
Шаг 4. Сообщение «No scheduled commands are ready to run» — это нормально?
При ручном запуске:
sail artisan schedule:run
или
php artisan schedule:run
вы можете увидеть сообщение:
INFO No scheduled commands are ready to run.
Это не ошибка. Дело в том, что Laravel каждый раз проверяет, пора ли запускать ваши задачи. Если вы, например, указали ->daily() (выполнение раз в сутки), а сейчас не полночь, то Scheduler просто сообщает, что "Нет задач, которым пора выполняться".
Чтобы протестировать саму логику вашей задачи (убедиться, что код в ->call(...) работает), можно:
- Поменять расписание на
->everyMinute(), временно. - Снова вызвать
schedule:run. - Убедиться, что задача действительно сработала (посмотреть изменения в базе, логи и т.д.).
Таким образом, если у вас в логах нет ошибок, а
schedule:runговорит «No scheduled commands are ready to run», скорее всего всё в порядке и задача просто «ждёт» своё время.
Шаг 5. Отладка и проверка
- Проверить, что команда действительно прописана
Если в проекте версия Laravel поддерживает команду:
php artisan schedule:listВы увидите список всех задач, зарегистрированных вKernelили в конфигурации через->withSchedule(). Если вашей задачи нет, убедитесь, что вы не забыли что-то импортировать или сделатьreturnв правильном месте. - Проверить логи
- Если задача выполняется, но при выполнении возникают ошибки, они часто пишутся в
storage/logs/laravel.log. - Если логи пусты, обычно это значит, что ошибок нет.
- Если задача выполняется, но при выполнении возникают ошибки, они часто пишутся в
- Проверить время на сервере
Иногда задачи не срабатывают, если системное время в конфигурации отличается от реального. Убедитесь, что команда:
dateпоказывает правильное локальное время. При необходимости проверьтеconfig/app.php:'timezone' => 'Europe/Moscow',или укажите нужный часовой пояс и перезапустите сервис/контейнер. - Убедиться, что код внутри задачи работает
Зайдите в
Tinkerи вручную попробуйте выполнить код:sail artisan tinker // или php artisan tinkerЗатем:use App\Models\Product; use Illuminate\Support\Carbon; Product::where('is_new', 1) ->where('is_new_set_at', '<=', Carbon::now()->subMonth()) ->update(['is_new' => 0]);Если код срабатывает и обновляет нужные записи, значит проблема точно не в самом коде.
Вывод
Настройка крон-задачи для Laravel 11 довольно проста, если понимать общую схему работы schedule:run и убедиться, что системная часть (cron) корректно запускается каждую минуту:
- Описать задачи в Laravel (через
Kernelили вbootstrap/app.php, как в новых версиях). - Добавить одну cron-запись для
php artisan schedule:run. - Следить за логами и не пугаться, если видите сообщение «No scheduled commands are ready to run» — это нормально, когда по текущему расписанию нет задач к запуску.
Если же вы используете Docker, то имейте в виду, что в контейнере по умолчанию может не быть
cron, и придётся добавить его вручную, а также прописать крон-задачи внутри самого контейнера. Успешного вам планирования задач!
Была статья полезной: