Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Итак, я пошел вперед и реализовал предложение Мартина. Вот bash script Я придумал.

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

Ответ 3

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

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

  • отправить сигнал HUP на сервер fcgi (полезно использовать аргумент pidfile = для запуска сервера)

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

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

  • Запустите сервер снова

Что это.

Ответ 5

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

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

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

  • закрывает сокет, который останавливает неактивные дочерние элементы
  • отправляет сигнал INT
  • ждет 10 секунд
  • отправляет сигнал KILL

Когда все дети уйдут, они начнут новые.

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

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