Fix container lifecycle: signals, worker queues, healthcheck - #850
Conversation
SIGTERM died in the shell wrapper, so nothing shut down warmly. The worker had no queue setting and its healthcheck never passed. Refs #802.
|
|
||
| CMD ["sh", "-c", "python manage.py migrate && uwsgi --master --http=:8000 --venv=/code/.venv/ --wsgi=app.wsgi --workers=2 --threads=2 --harakiri=25 --max-requests=1000 --log-x-forwarded-for --logformat '%(addr) - - [%(ltime)] \"%(method) %(uri) %(proto)\" %(status) %(size) \"%(referer)\" \"%(uagent)\"'"] | ||
| CMD ["sh", "-c", "python manage.py migrate \ | ||
| && exec uwsgi \ |
There was a problem hiding this comment.
Здесь и в других местах: exec убирает sh из цепочки tini → sh → приложение.
Почему нужно: dash (shell-оболочка в контейнере) не передаёт SIGTERM дальше, а выходит сам, и uwsgi с celery про остановку не узнают. То есть когда добавили tini, контейнеры стали быстро завершаться, но по факту убивались, т.к. сигнал для корректной остановки не доходил до приложения.
| CMD ["sh", "-c", "python manage.py migrate \ | ||
| && exec uwsgi \ | ||
| --master \ | ||
| --die-on-term \ |
There was a problem hiding this comment.
без этого uwsgi релоадит воркеров, а не останавливается
| CMD ["sh", "-c", "exec celery \ | ||
| --app=${_CELERY_APP} \ | ||
| worker \ | ||
| --queues=${QUEUES:-celery} \ |
There was a problem hiding this comment.
Добавил флаг с очередями. Его не было, и чтобы запустить второй воркер на другой очереди, приходилось переписывать CMD в Dockerfile. Теперь очередь задаётся через QUEUES, а по умолчанию всё как раньше — celery
| CMD celery --app=${_CELERY_APP} inspect ping --destination=$QUEUE@$HOSTNAME | ||
|
|
||
| CMD ["sh", "-c", "celery --app=${_CELERY_APP} worker --concurrency=${CONCURRENCY:-2} --hostname=celery@%h --max-tasks-per-child=${MAX_REQUESTS_PER_CHILD:-50} --time-limit=${TIME_LIMIT:-900} --soft-time-limit=${SOFT_TIME_LIMIT:-45}"] | ||
| CMD celery --app=${_CELERY_APP} inspect ping --destination=${WORKER_NAME:-celery}@$HOSTNAME |
There was a problem hiding this comment.
Тут поправили healthcheck у воркеров: было$QUEUE@$HOSTNAME, но $QUEUE никто не выставляет — оставалось @hostname и хэлсчек падал.
| ENV _CELERY_APP=app.celery | ||
| HEALTHCHECK NONE | ||
| CMD ["sh", "-c", "celery --app=${_CELERY_APP} beat --pidfile=/tmp/celerybeat.pid --schedule=${_SCHEDULER_DB_PATH}/celerybeat-schedule.db"] | ||
| CMD ["sh", "-c", "exec celery \ |
There was a problem hiding this comment.
Здесь и везде переписал аргументы в столбик: так понятнее дифы и блеймы смотреть, что к чему относиться и комментить в PR :)
|
fyi: @kazqvaizer, @f213 |
#844 added tini and closed #802, but the signal still does not arrive:
tini hands SIGTERM to the shell, and the shell dies without passing it on.
Signals never reach the app —
execin all three CMDs.sh -c "..."stays the parent and takes SIGTERM for itself.Celery and uwsgi are killed together with the container, with no warm shutdown: in-flight tasks and requests are lost.
uwsgi reloads on SIGTERM instead of exiting —
--die-on-term.execalone makes it worse: the signal arrives, uwsgi reloads its workers and hangs until SIGKILL 10 seconds later.Worker is nailed to a single queue —
--queues=${QUEUES:-celery},--hostname=${WORKER_NAME:-celery}@%h.The queue was not set at all and the hostname was hardcoded.
A project with several queues no longer has to rewrite the CMD.
Worker healthcheck is always red —
--destination=${WORKER_NAME:-celery}@$HOSTNAME.It was
$QUEUE@$HOSTNAME, and nothing ever sets$QUEUE, so it stayed@hostname.celery inspect pinganswersNo nodes replied, exit 69.Params are also split one per line: there are many of them, and on a single line you cannot see what changed.