Django框架 - 是否有可订阅的关机事件?
我遇到了一个问题,希望能通过在Django中使用某种形式的关闭钩子来解决。
我还是Python/Django开发的新手,为了帮助自己学习,我给自己设定了一个项目,开发一个在浏览器中运行的COMET/反向Ajax风格的聊天网站。这个网站会不断向服务器请求消息。当服务器收到请求时,它会检查是否有等待的消息。如果没有消息,它会尝试获取一个已经被占用的threading.Lock对象的锁。这会导致处理请求的线程被阻塞,直到收到消息并释放之前提到的锁。
我的问题出现在我关闭服务器的时候。目前我使用的是开发服务器(python manage.py runserver)。如果有一个线程因为上面提到的过程而被阻塞,那么服务器就无法关闭。
有没有办法让我在服务器尝试关闭时执行一些代码,以便释放任何等待的线程呢?
我查看过一个类似的问题,但没有找到帮助。有人猜测可能没有这样的事件钩子,但没有明确的答案。我在网上搜索了很多,但没有找到解决办法。
我使用的是Python 2.7和Django 1.5。
非常感谢你能提供的任何帮助。
2 个回答
Stu Gla的回答补充:
在Django的主线程中设置信号事件的处理程序,你可以把处理的初始化放在manage.py文件或者你应用的__init__.py文件里,像这样:
# {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)
这样你就可以在不加--noreload的情况下运行服务器了。
检查一下os.environ.get('RUN_MAIN')
,这个函数会被调用两次。
我不知道有没有一个关闭事件,但你可以自己创建一个。
当用户按下Ctrl-C时,Python进程会收到一个叫做SIGINT的信号。你可以在你的 wsgi.py
文件中设置一个信号处理器,来捕捉这个SIGINT信号,并把它转发给你的程序。
wsgi.py:
...
import signal
signal.signal(signal.SIGINT, my_signal_handler)
你甚至可以把这个信号转发给Django的信号:
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)
因为 signal
只能在主线程中调用,所以在使用runserver时这个方法是行不通的。你可以选择用 --noreload
选项来运行runserver,或者换用gunicorn。