Как изящно перезапустить django, работающий fcgi за nginx?

Я запускаю экземпляр django за nginx, подключенным с помощью fcgi (используя manage.py команда runfcgi). Поскольку код загружен в память, я не могу перезагрузить новый код без убийства и перезапуска процессов django fcgi, тем самым прерывая живой веб-сайт. Сам перезапуск очень быстрый. Но, убив процессы fcgi сначала, некоторые действия пользователей будут прерваны, что нехорошо. Мне интересно, как я могу перезагрузить новый код, не вызывая прерывания. Советы будем очень признательны!

5 ответов


Я бы начал новый процесс fcgi на Новом Порту, изменил конфигурацию nginx, чтобы использовать новый порт, иметь конфигурацию перезагрузки nginx (что само по себе изящно), а затем в конечном итоге остановить старый процесс (вы можете использовать netstat, чтобы узнать, когда последнее соединение со старым портом закрыто).

кроме того, вы можете изменить реализацию fcgi на вилку нового процесса, закрыть все сокеты в дочернем, за исключением сокета сервера fcgi, закрыть сокет сервера fcgi в Родительском, выполните новый процесс django в дочернем (используя сокет сервера fcgi) и завершите родительский процесс после закрытия всех соединений fcgi. IOW, реализовать изящный перезапуск для runfcgi.


поэтому я пошел вперед и реализовал предложение Мартина. Вот сценарий bash, который я придумал.

pid_file=/path/to/pidfile
port_file=/path/to/port_file
old_pid=`cat $pid_file`

if [[ -f $port_file ]]; then
    last_port=`cat $port_file`
    port_to_use=$(($last_port + 1))
else
    port_to_use=8000
fi

# Reset so me don't go up forever
if [[ $port_to_use -gt 8999 ]]; then
    port_to_use=8000
fi

sed -i "s/$old_port/$port_to_use/g" /path/to/nginx.conf

python manage.py runfcgi host=127.0.0.1 port=$port_to_use maxchildren=5 maxspare=5 minspare=2 method=prefork pidfile=$pid_file

echo $port_to_use > $port_file

kill -HUP `cat /var/run/nginx.pid`

echo "Sleeping for 5 seconds"
sleep 5s

echo "Killing old processes on $last_port, pid $old_pid"
kill $old_pid

я наткнулся на эту страницу, ища решение этой проблемы. Все остальное не удалось, поэтому я заглянул в исходный код:)

решение кажется намного проще. Сервер Django fcgi использует flup, который обрабатывает сигнал HUP надлежащим образом: он выключается, изящно. Поэтому все, что вам нужно сделать, это:

  1. отправить сигнал HUP на сервер fcgi (pidfile= аргумент runserver пригодится)

  2. ждать немного (flup позволяет детям обрабатывать 10 секунд, поэтому подождите еще пару; 15 выглядит как хорошее число)

  3. отправил сигнал убийства на сервер fcgi, на всякий случай, если что-то заблокировало его

  4. запустите сервер


вы можете использовать нерест вместо FastCGI

http://www.eflorenzano.com/blog/post/spawning-django/


мы, наконец, нашли правильное решение этого!

http://rambleon.usebox.net/post/3279121000/how-to-gracefully-restart-django-running-fastcgi

сначала отправьте flup сигнал HUP для сигнала перезапуска. Затем Flup сделает это со всеми своими детьми:

  1. закрывает сокет, который не активен детей
  2. посылает сигнал INT
  3. ждет 10 секунд
  4. отправляет убийство сигнал

когда все дети ушли, он начнет новые.

это работает почти все время, за исключением того, что если ребенок обрабатывает запрос, когда flup выполняет шаг 2 тогда ваш сервер умрет с KeyboardInterrupt, выдает 500 ошибку.

решение заключается в установке обработчика SIGINT-Подробнее см. На странице выше. Даже просто игнорирование SIGINT дает вашему процессу 10 секунд для выхода, что достаточно для большинства запросов.