Как перезапустить Celery изящно, не затягивая задачи
Мы используем Celery с нашим веб-приложением Django для управления автономными задачами; некоторые из этих задач могут выполняться до 120 секунд.
Когда бы мы ни делали какие-либо модификации кода, нам нужно перезапускать Celery, чтобы он перезагрузил новый код Python. Наше текущее решение - отправить SIGTERM в основной процесс Celery (kill -s 15 `cat /var/run/celeryd.pid`
), затем дождаться его смерти и перезапустить (python manage.py celeryd --pidfile=/var/run/celeryd.pid [...]
).
Из-за длительных задач это обычно означает, что завершение работы займет минуту или две, в течение которых новые задачи не обрабатываются, что приводит к заметной задержке для пользователей, которые в настоящее время находятся на сайте. Я ищу способ сообщить Celery о завершении работы, но затем немедленно запустить новый экземпляр Celery, чтобы начать выполнение новых задач.
Вещи, которые не работали:
- Отправка SIGHUP основному процессу: это заставило Celery попытаться "перезапустить", сделав теплое завершение работы и затем перезапустив себя. Мало того, что это занимает много времени, это даже не работает, потому что, очевидно, новый процесс запускается до того, как старый умирает, поэтому новый жалуется
ERROR: Pidfile (/var/run/celeryd.pid) already exists. Seems we're already running? (PID: 13214)
и сразу умирает. (Это похоже на ошибку в самом Celery; я дал им знать об этом.) - Отправка SIGTERM основному процессу, а затем немедленный запуск нового экземпляра: та же проблема с Pidfile.
- Полное отключение Pidfile: без него мы не сможем сказать, какой из 30 процессов Celery является основным процессом, который необходимо отправить в SIGTERM, когда мы хотим, чтобы он выполнял теплое завершение работы. У нас также нет надежного способа проверить, жив ли основной процесс.
7 ответов
У celeryd есть опция --autoreload. Если этот параметр включен, работник сельдерея (основной процесс) будет обнаруживать изменения в модулях сельдерея и перезапускать все рабочие процессы. В отличие от сигнала SIGHUP, автозагрузка перезапускает каждый процесс независимо, когда текущая задача завершается. Это означает, что пока один рабочий процесс перезапускает, остальные процессы могут выполнять задачи.
http://celery.readthedocs.org/en/latest/userguide/workers.html
Я недавно исправил ошибку с SIGHUP: https://github.com/celery/celery/pull/662
rm *.pyc
Это приводит к перезагрузке обновленных задач. Я обнаружил этот трюк недавно, я просто надеюсь, что нет никаких неприятных побочных эффектов.
Ну, вы используете SIGHUP (1) для теплого отключения сельдерея. Я не уверен, что это на самом деле вызывает горячее отключение. Но SIGINT (2) может вызвать горячее отключение. Попробуйте SIGINT вместо SIGHUP, а затем запустите сельдерей вручную в своем сценарии (я полагаю).
Немного поздно, но это можно исправить, удалив файл с именем celerybeat.pid.
Работал на меня.
Можете ли вы запустить его с пользовательским именем файла PID. Возможно, отметка времени и ключ к тому, чтобы узнать, какой PID убить?
CELERYD_PID_FILE="/var/run/celery/%n_{timestamp}.pid"
^ Я не знаю синтаксис метки времени, но, может быть, вы знаете или можете его найти?
затем использовать текущее системное время, чтобы уничтожить старые пиды и запустить новый?
Я думаю, что вы можете попробовать это:
kill -s HUP ``cat /var/run/celeryd.pid``
python manage.py celeryd --pidfile=/var/run/celeryd.pid
HUP
может перерабатывать каждого свободного работника и оставлять рабочих-исполнителей продолжать работать и HUP
позволит этим работникам доверять. Тогда вы можете безопасно перезапустить новый рабочий процесс сельдерея и основных рабочих. Старые рабочие могут быть убиты, когда задание выполнено.
Я использую этот способ в нашем производстве, и теперь это кажется безопасным. Надеюсь, это поможет вам!