Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Framework - Is there a shutdown event that can be subscribed to?

Tags:

python

django

web

I have a problem which I am hoping might be solved with some form of shutdown hook in Django.

I am still a beginner with Python/Django development, and to help learn I have set myself a project of developing a COMET/Reverse Ajax style chat site that runs in browser. The browser continuously polls the server for any messages. When the server receives a poll request, it checks to see if there are any messages waiting, and if there are none, it will attempt to acquire a lock on a threading.Lock object which has already been acquired. This causes the thread which is handling the request to block until a message is received and the previously mentioned lock is released.

My problem arises when I shutdown the server. At this point I am using the development server (python manage.py runserver). If there is a thread blocked from the above explained process, then the server does not shutdown.

Is there a way that i can execute code when the server attempts to shutdown so that i can release any waiting threads?

I have looked at the following similar question however it hasn't helped me. There was speculation that such an event hook does not exist, however no definitive answer. I've googled high and low, but haven't had any luck.

I am using Python 2.7 and Django 1.5.

Grateful for any help you can provide

like image 280
Mike B Avatar asked Mar 18 '13 08:03

Mike B


2 Answers

I don't know of a shutdown event, but you can create one.

When the user presses Ctrl-C, a SIGINT signal is sent to Python process. Setup a signal handler from your wsgi.py file to catch the SIGINT and forward it to your program.

wsgi.py:

...

import signal
signal.signal(signal.SIGINT, my_signal_handler)

You could even forward the signal to a django signal:

my_django_shutdown_signal = django.dispatch.Signal()

def _forward_to_django_shutdown_signal(signal, frame):
    my_django_shutdown_signal.send('system')
    sys.exit(0)   # So runserver does try to exit
signal.signal(signal.SIGINT, _forward_to_django_shutdown_signal)

Since signal can only be called from the main thread, this won't work with runserver. Either call runserver with the --noreload option, or switch over to gunicorn.

like image 178
Stu Gla Avatar answered Sep 19 '22 14:09

Stu Gla


Addition to answer by Stu Gla:
To set handler for signal event in main thread in django you can put put initialization of handling to manage.py or your app's __init__.py, like so:

#  {project_root}/{your_app}/__init__.py
import os  
import signal  
import sys  
def my_signal_handler(*args):  
    if os.environ.get('RUN_MAIN') == 'true':  
        print('stopped'.upper())  
    sys.exit(0) 

signal.signal(signal.SIGINT, my_signal_handler)  

It will let you run server without --noreload.
Check for os.environ.get('RUN_MAIN') pvevent calling function 2 times.

like image 39
Артём Слободкин Avatar answered Sep 16 '22 14:09

Артём Слободкин