A worker container killed after ten seconds on every deploy, because the signal never reached the process.
# the problem
CMD php artisan queue:work
# → the shell is PID 1, php is a child, SIGTERM goes to
# the shell, which does not forward it
# the fix
CMD ["php", "artisan", "queue:work"]
# → exec form: php is PID 1 and receives the signal
# and the second half
STOPSIGNAL SIGTERM
# with stop_grace_period: 60s in the compose file
Shell form versus exec form is the difference between a graceful shutdown and a kill, and both look identical in every log until a job is interrupted mid-flight. The grace period matters as much: ten seconds is the default and our longest job is forty, so a correctly signalled worker was still being killed for the same visible result.