16π
I would start a new fcgi process on a new port, change the nginx configuration to use the new port, have nginx reload configuration (which in itself is graceful), then eventually stop the old process (you can use netstat to find out when the last connection to the old port is closed).
Alternatively, you can change the fcgi implementation to fork a new process, close all sockets in the child except for the fcgi server socket, close the fcgi server socket in parent, exec a new django process in the child (making it use the fcgi server socket), and terminate the parent process once all fcgi connections are closed. IOW, implement graceful restart for runfcgi.
16π
So I went ahead and implemented Martinβs suggestion. Here is the bash script I came up with.
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]-Django Model() vs Model.objects.create()
- [Django]-How to use UUID
- [Django]-Django equivalent of PHP's form value array/associative array
10π
I came across this page while looking for a solution for this problem. Everything else failed, so I looked in to the source code π
The solution seems to be much simpler. Django fcgi server uses flup, which handles the HUP signal the proper way: it shuts down, gracefully. So all you have to do is to:
-
send the HUP signal to the fcgi server (the pidfile= argument of runserver will come in handy)
-
wait a bit (flup allows children processes 10 seconds, so wait a couple more; 15 looks like a good number)
-
sent the KILL signal to the fcgi server, just in case something blocked it
-
start the server again
Thatβs it.
- [Django]-How do I use a dictionary to update fields in Django models?
- [Django]-Django Projects as Desktop applications : how to?
- [Django]-Django cannot import login from django.contrib.auth.views
- [Django]-Empty Request.FILES with Django Upload forms
- [Django]-Django serializer inherit and extend fields
- [Django]-Login with code when using LiveServerTestCase with Django
2π
We finally found the proper solution to this!
http://rambleon.usebox.net/post/3279121000/how-to-gracefully-restart-django-running-fastcgi
First send flup a HUP signal to signal a restart. Flup will then do this to all of its children:
- closes the socket which will stop inactive children
- sends a INT signal
- waits 10 seconds
- sends a KILL signal
When all the children are gone it will start new ones.
This works almost all of the time, except that if a child is handling a request when flup executes step 2
then your server will die with KeyboardInterrupt
, giving the user a 500 error.
The solution is to install a SIGINT handler β see the page above for details. Even just ignoring SIGINT gives your process 10 seconds to exit which is enough for most requests.
- [Django]-Bypass confirmation prompt for pip uninstall
- [Django]-How to override and extend basic Django admin templates?
- [Django]-Django 1.7 β "No migrations to apply" when run migrate after makemigrations