CrazyPython
6/26/2015 - 2:16 PM

Shutdown middleware for django on Heroku. See http://stackoverflow.com/questions/30969597/how-do-i-handle-dyno-restarts-when-using-django/31

from django.http import HttpResponse

_current_shutdown_middleware = None

# Used in situations where it must shutdown before it gets initialized
_pre_shutdown = False

class ShutdownMiddleware(object):
    shutting_down = False

    def __init__(self):
        _current_shutdown_middleware = self
        if _pre_shutdown:
            self.shutting_down = True
    
    @staticmethod
    def shutdown_switch():
        """Activate the shutdown switch"""
        self = current_shutdown_middleware
        try:
            self.shutting_down = True
        except AttributeError:
            # Has not processed first request, requesting shutdown
            sys.stderr.write('[ShutdownMiddleware.shutdown_switch] Requested Shutdown, not yet initialized.\n')
            _pre_shutdown = True

    def process_request(self, request):
        if self.shutting_down:
            return HttpResponse('500 internal server error\n'
                         'Server restarting; please try again in 10 seconds.\n', status=500, content_type='text/plain')
        else:
            return None

Hello! I created this gist to demonstrate how you can handle Heroku dyno restarts in Django. This is based off of this stackoverflow question. Many thanks to the writer of the awnser. To put activate the Middleware, you must put this in your django settings file:

MIDDLEWARE_CLASSES = (
    'Middleware.ShutdownMiddleware',
    # All the prexisting classes
    ...
)

You should probably put this at the top so you can return the 500 error instantly, but if you have something like SSLify you may want to put that at the top, but it puts a small barrier between you and the instant server-wide 500 error. That's it!

Thanks to everybody mentioned on the stackoverflow question, including the OP.

Bye! ~CrazyPython

from django.http import HttpResponse
from Middleware import ShutdownMiddleware
import signal
import sys

class TerminationManager(object):

    def __init__(self):
        self._running = True
        signal.signal(signal.SIGTERM, self._start_shutdown)

    def _start_shutdown(self, signum, stack):
        sys.stderr.write('[TerminationManager] Recieved SIGTERM. Stopping new requests.')
        self._running = False
        ShutdownMiddleware.shutdown_switch()
        
termination_manager = TerminationManager()

def dummy_view(request):
    return HttpResponse('Hello! I am a dummy.', content_type='text/plain')