Seamlessly switch off (and on) a Django (or other WSGI) site for upgrades
May 25th, 2009 by tobiasIn preparation for migrating the EveryWatt database from one machine to another, I wrote this little WSGI script to easily disable the site while I copy the data. Since it doesn’t depend on Django or really anything else (other than a functioning WSGI server), you can use it for other upgrades, too.
This is useful for preventing updates to the database while you, for example, dump the database on one machine and load it on another. With everything else already in place on either side, the user should only see the “Upgrade in progress” message for a few minutes.
Since EveryWatt includes a number of data logger clients that upload utility meter readings to the site through its Open API, I wanted to make sure any POST attempts received a temporary failure message (the data logger will store the data and retry the POST every minute)–hence the 405 Method Not Allowed for all non-GET requests.
Here’s the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import os import sys UPGRADING = False #Calculate the project path based on the location of the WSGI script. project_dir = os.path.dirname(__file__) sys.path.append(project_dir) def upgrade_in_progress(environ, start_response): upgrade_file = os.path.join(project_dir, 'media', 'html', 'upgrade.html') if os.path.exists(upgrade_file): response_headers = [('Content-type','text/html')] response = open(upgrade_file).read() else: response_headers = [('Content-type','text/plain')] response = 'Application upgrade in progress...please check back soon.' if environ['REQUEST_METHOD'] == 'GET': status = '503 Service Unavailable' else: status = '405 Method Not Allowed' start_response(status, response_headers) return [response] if UPGRADING: application = upgrade_in_progress else: os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler() |
And in case you need it, here’s one way to dump a PostgreSQL database on one machine while you load it on another, to be run on the new host, as the database superuser:
1 | pg_dump -h <old host> -U <user> <old database> | psql <new database> |
Good luck and please post your questions/comments.


May 26th, 2009 at 10:35 am
Nice. It should return a 503 Service Unavailable status code rather than 200 OK, else you run the risk of a crawler indexing your “upgrading” page. Using the 503 status code won’t affect browsers displaying the content of the temp page.
If you really want to be HTTP-friendly, you’d optionally add a Retry-After header to indicate how long the maintenance is expected to take.
May 26th, 2009 at 10:44 am
Good call, thanks. I updated the code to return a 503 instead of a 200.
May 27th, 2009 at 4:23 am
I’d also suggest returning 405 Method Not Allowed rather than 403 Forbidden if the URL is called with something other than GET.
May 27th, 2009 at 8:20 am
That sounds reasonable, thanks. 405 Method Not Allowed sounded more permanent to me originally (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html), since POST is normally a valid method. From what I understand, most of the 4xx error codes can be either temporary or permanent, as long as the body indicates which it is. Post updated.