15

我有一个问题,我希望可以通过 Django 中的某种形式的关闭挂钩来解决。

我仍然是 Python/Django 开发的初学者,为了帮助学习,我为自己设置了一个项目,开发一个在浏览器中运行的 COMET/Reverse Ajax 风格的聊天网站。浏览器不断地轮询服务器以获取任何消息。当服务器收到一个轮询请求时,它会检查是否有任何消息在等待,如果没有,它会尝试获取一个已经获取的threading.Lock对象的锁。这会导致处理请求的线程阻塞,直到收到消息并释放前面提到的锁。

当我关闭服务器时,我的问题出现了。此时我正在使用开发服务器(python manage.py runserver)。如果有一个线程被上述进程阻塞,则服务器不会关闭。

有没有一种方法可以在服务器尝试关闭时执行代码,以便我可以释放任何等待的线程?

我已经查看了以下类似的问题,但它并没有帮助我。有人猜测这样的事件挂钩不存在,但没有明确的答案。我用谷歌搜索了高低,但没有任何运气。

我正在使用 Python 2.7 和 Django 1.5。

感谢您提供的任何帮助

4

2 回答 2

14

我不知道关闭事件,但您可以创建一个。

当用户按下 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。使用该选项调用 runserver --noreload,或切换到 gunicorn。

于 2013-12-17T23:43:52.873 回答
3

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')pvevent 调用函数 2 次。

于 2018-01-31T10:49:40.717 回答