Чим PHP CLI відрізняється від PHP-FPM для завдань cron
PHP-FPM обслуговує HTTP-запити через Nginx і працює в режимі пулу воркерів зі спільним php.ini та лімітами, заданими для вебнавантаження. PHP CLI — це окремий бінарник /usr/bin/php8.3, який запускається з командного рядка або з crontab і читає свій власний конфіг, зазвичай із /etc/php/8.3/cli/php.ini. Значення memory_limit, max_execution_time і error_reporting у CLI та FPM можуть відрізнятися, і це часта причина, чому скрипт у браузері працює, а той самий скрипт за розкладом падає або навпаки.
Друга відмінність — оточення. У процесу cron немає змінних PATH, HOME і локалі, які є в інтерактивній оболонці, і немає робочого каталогу за замовчуванням: він завжди стартує з домашнього каталогу користувача, від імені якого запущено cron.
Як правильно прописати завдання у crontab
Правило crontab повинно вказувати повний шлях до бінарника PHP, повний шлях до скрипту і робочий каталог, якщо скрипт використовує відносні шляхи до файлів.
*/5 * * * * cd /var/www/app && /usr/bin/php8.3 artisan schedule:run >> /var/log/app/cron.log 2>&1
Символ && гарантує, що php запуститься лише після успішного переходу в каталог, а 2>&1 перенаправляє помилки в той самий лог-файл, що і звичайний вивід. Без цього фатальні помилки PHP тихо зникають: cron надсилає їх на локальну пошту, яку ніхто не читає.
Власна версія php.ini для CLI
Перевірити, який конфіг насправді використовує CLI, можна однією командою — вона покаже шлях до файлу, а не припущення.
php --ini
php -i | grep memory_limit
Якщо на сервері встановлено кілька версій PHP, як описано у статті про кілька версій PHP на одному сервері, у crontab обов'язково вказуйте версію явно: /usr/bin/php8.3, а не просто php — інакше завдання може несподівано виконатися під іншою версією після оновлення alternatives.
Пам'ять, таймаути і робочий каталог: часті пастки
| Параметр | Веб (FPM) | Cron (CLI) |
|---|---|---|
| memory_limit | 128M | часто без обмеження (-1) |
| max_execution_time | 30 секунд | 0, обмеження немає |
| робочий каталог | корінь сайту | домашній каталог користувача |
| error_log | лог PHP-FPM | stderr, якщо не задано явно |
Значення з таблиці задаються в різних секціях php.ini: [PHP] впливає на обидва режими, а блок cli/conf.d — лише на CLI. Керування пам'яттю і завантаженням докладно розібрано у статті про memory_limit і upload_max_filesize.
Журналювання виводу завдань cron
- Завжди перенаправляйте stdout і stderr в окремий файл журналу, а не покладайтеся на пошту cron.
- Вказуйте display_errors = Off і log_errors = On у cli/php.ini — вивід помилок у консоль ламає формат, якщо скрипт друкує JSON чи CSV.
- Ротацію лог-файлу cron налаштовуйте через logrotate, інакше файл виросте до гігабайтів за місяць.
- Розбір завдань, що впали, починайте з error_log, а не з припущень — принципи розібрані у статті про логи PHP і розбір фаталів.
- Додавайте на початок кожного завдання date і hostname в журнал — на кластері з кількох серверів інакше не зрозуміти, хто саме писав у журнал.
Підсумок: чек-лист для PHP-завдань у cron
- У crontab вказано повний шлях до бінарника потрібної версії PHP і робочий каталог через cd.
- Вивід команди перенаправлено у файл журналу з ротацією через logrotate.
- Перевірені memory_limit і max_execution_time саме у cli/php.ini, а не в конфігу FPM.
- display_errors вимкнено, log_errors увімкнено, помилки йдуть у файл, а не в пошту root.
- Завдання перевірене вручну від імені того самого користувача, від якого його запускає cron.