docker stop надсилає головному процесу контейнера (PID 1) сигнал SIGTERM і чекає (за замовчуванням 10 секунд). Якщо процес не завершився - надсилає SIGKILL, який не можна перехопити: усе обривається на півдорозі.
Чому SIGTERM не доходить до застосунку:
- Shell-форма команди.
CMD php artisan queue:workзапускається як/bin/sh -c "...". PID 1 - оболонка, аshне передає сигнали дочірнім процесам. Воркер не дізнається, що треба зупинитися. - Скрипт-обгортка без
exec.entrypoint.sh, що просто викликаєphp-fpmв кінці, лишається PID 1, а FPM - його дочірнім процесом. - PID 1 особливий у ядрі: для нього сигнали без явно встановленого обробника ігноруються. Процес, що не обробляє
SIGTERM, ставши PID 1, не завершиться від нього.
Рішення:
CMD ["php", "artisan", "queue:work"] # exec-форма: процес - PID 1
#!/bin/sh
# entrypoint.sh
php artisan config:cache
exec "$@" # замінити оболонку командою, а не запустити дочірній процес
--init(init: trueу Compose) додає крихітний init-процес (tini) як PID 1: він пересилає сигнали й прибирає процеси-зомбі.stop_grace_period- більше часу, якщо коректне завершення справді довге.
Навіщо це на практиці: воркер черги, що отримав SIGTERM, доробляє поточне завдання й завершується. Убитий SIGKILL - обриває його посередині: напівзапис у базу, повторне виконання після рестарту. Тому --timeout воркера, stop_grace_period і ліміти оркестратора налаштовують узгоджено. Те саме для PHP-FPM (SIGQUIT - м'яке завершення) і Octane.