如何阻止Django开发服务器重启?

时间:2018-02-08 08:25:45

标签: django

我希望Django开发服务器在发生错误时退出。但是每当服务器退出时,它都会重新启动。我试图使用os.kill(os.getpid,9)杀死进程,但这不起作用。我尝试了sys.exit,os._exit,并引发了错误,但没有一个工作。

注意: 由于该程序不仅仅在Linux上运行,所以理想情况下我不希望使用像bash这样的东西。我也不想破坏其他程序。

1 个答案:

答案 0 :(得分:0)

开发服务器在出错时不会重新启动,它只是处理异常并继续运行,就像生产服务器那样。这是它应该的方式 - HTTP是无状态的,一个请求中的错误不应该影响下一个请求。

所以你需要注意的是,无论你做什么,你可能会滥用runserver ,而且几乎肯定会有更好的方式这样做。

那说:

有几个地方阻止服务器在出错时退出。

首先,Django将每个请求包装在django.core.handlers.exception.convert_exception_to_response函数中,该函数捕获每个Exception并将其转换为良好的响应。因此,要通过此操作,您需要引发错误not derived from Exception,例如KeyboardInterruptSystemExit

然后有django.core.servers.basehttp.ServerHandler,它派生自wsgiref.handers.BaseHandler,它将请求包装在try: ... except: ...中以捕获所有异常,并再次将它们转换为响应。由于您可能仍希望获得该响应,因此在生成错误响应后,您必须修改handle_error方法以再次引发错误

不幸的是,那里有很多耦合。 ServerHandler类被硬编码为django.core.servers.basehttp.WSGIRequestHandler.handle,其被硬编码为django.core.server.basehttp.run,其被硬编码为django.core.management.commands.runserver。因此,您要么必须复制所有代码(这基本上是Django所做的,从wsgiref复制一些代码),或者您还要进行猴子修补。

然后还有django.core.servers.basehttp.WSGIServer,它是socketserver.BaseServer的子类。我们刚刚重新提出的例外情况发送到WSGIServer.handle_error,它试图将其变为响应并继续。所以你需要覆盖它。

然后它应该工作,只要您运行没有线程和自动重新加载的服务器,运行从runserver派生的自定义命令,如:

import sys
from django.core.management.commands import runserver
from django.core.servers.basehttp import ServerHandler, is_broken_pipe_error, WSGIServer


good_handle_error = ServerHandler.handle_error
def bad_handle_error(self):
    if not is_broken_pipe_error():
        good_handle_error(self)
        sys.exit(1)
ServerHandler.handle_error = bad_handle_error


class BadWSGIServer(WSGIServer):
    def handle_error(self, request, client_address):
        if is_broken_pipe_error():
            super().handle_error(self, request, client_address)
        else:
            sys.exit(1)


class Command(runserver.Command):
    server_cls = BadWSGIServer

    def handle(self, *args, **options):
        options['use_reloader'] = False
        options['use_threading'] = False
        super().handle(*args, **options)