На звичайному сервері планувальник запускається рядком у crontab:
* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1
schedule:run щохвилини перевіряє, які задачі настав час виконати, і завершується.
У Docker є два підходи.
1. schedule:work - окремий контейнер (рекомендовано):
services:
scheduler:
image: myapp:1.4.0
command: php artisan schedule:work
restart: unless-stopped
schedule:work - процес на передньому плані, який сам щохвилини викликає schedule:run. Не потрібен cron-демон, вивід іде в stdout (видно в docker logs), сигнали зупинки обробляються коректно.
2. cron усередині контейнера:
RUN apt-get install -y cron && echo "* * * * * www-data php /var/www/html/artisan schedule:run" > /etc/cron.d/laravel
CMD ["cron", "-f"]
Недоліки: cron не передає дочірнім процесам змінні оточення контейнера (треба їх окремо зберігати й підставляти), вивід задач не потрапляє в логи Docker, потрібен root для cron-демона.
3. Зовнішній планувальник - cron на хості, Kubernetes CronJob чи планувальник платформи запускає разовий контейнер з php artisan schedule:run. Корисно, якщо платформа не любить постійно запущених процесів без роботи.
Обов'язкові правила:
- рівно один планувальник. Якщо масштабувати контейнер
schedulerдо двох реплік чи запускатиschedule:runу кожному вебконтейнері, кожна задача виконається кілька разів - листи підуть двічі, звіти згенеруються двічі; - для задач, які взагалі не можна дублювати, -
->onOneServer()(атомарне блокування в спільному кеші) і->withoutOverlapping(), щоб довга задача не стартувала вдруге, поки працює перша; - довгі задачі - в черзу (
->runInBackground()чи задача, що ставить job), щоб не блокувати інші задачі цієї хвилини; - таймзона:
->timezone('Europe/Kyiv')чиschedule_timezoneу конфігурації - інакше «щодня о 9:00» означатиме 9:00 UTC.