Python:Django: Signal handler and main thread
Asked Answered
S

4

11

I am building a django application which depends on a python module where a SIGINT signal handler has been implemented.

Assuming I cannot change the module I am dependent from, how can I workaround the "signal only works in main thread" error I get integrating it in Django ?

Can I run it on the Django main thread? Is there a way to inhibit the handler to allow the module to run on non-main threads ?

Thanks!

Schnozzle answered 20/12, 2011 at 8:51 Comment(1)
I have the same problem. The weird part is that I'm pretty sure I'm not using any threads. I'm just running manage.py runserver.Filing
T
6

Django's built-in development server has auto-reload feature enabled by default which spawns a new thread as a means of reloading code. To work around this you can simply do the following, although you'd obviously lose the convenience of auto-reloading:

python manage.py runserver --noreload

You'll also need to be mindful of this when choosing your production setup. At least some of the deployment options (such as threaded fastcgi) are certain to execute your code outside main thread.

Taxi answered 3/1, 2013 at 16:23 Comment(0)
S
3

I use Python 3.5 and Django 1.8.5 with my project, and I met a similar problem recently. I can easily run my xxx.py code with SIGNAL directly, but it can't be executed on Django as a package just because of the error "signal only works in main thread".

Firstly, runserver with --noreload --nothreading is usable but it runs my multi-thread code too slow for me.

Secondly, I found that code in __init__.py of my package ran in the main thread. But, of course, only the main thread can catch this signal, my code in package can't catch it at all. It can't solve my problem, although, it may be a solution for you.

Finally, I found that there is a built-in module named subprocess in Python. It means you can run a sub real complete process with it, that is to say, this process has its own main thread, so you can run your code with SIGNAL easily here. Though I don't know the performance with using it, it works well for me. PS, you can find all details about subprocess in Python Documentation.

Thank you~

Senna answered 20/1, 2016 at 2:31 Comment(0)
B
2

There is a cleaner way, that doesn't break your ability to use threads and processes.

Put your registration calls in manage.py:

def handleKill(signum, frame):
    print "Killing Thread."
    # Or whatever code you want here
    ForceTerminate.FORCE_TERMINATE = True 
    print threading.active_count()
    exit(0)


if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

from django.core.management import execute_from_command_line

signal.signal(signal.SIGINT, handleKill)
signal.signal(signal.SIGTERM, handleKill)

execute_from_command_line(sys.argv)
Befoul answered 22/3, 2018 at 9:44 Comment(0)
C
0

Although the question does not describe exactly the situation you are in, here is some more generic advice:

The signal is only sent to the main thread. For this reason, the signal handler should be in the main thread. From that point on, the action that the signal triggers, needs to be communicated to the other threads. I usually do this using Events. The signal handler sets the event, which the other threads will read, and then realize that action X has been triggered. Obviously this implies that the event attribute should be shared among the threads.

Cholula answered 6/1, 2012 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.