我希望Django开发服务器在发生错误时退出。但是每当服务器退出时,它都会重新启动。我试图使用os.kill(os.getpid,9)杀死进程,但这不起作用。我尝试了sys.exit,os._exit,并引发了错误,但没有一个工作。
注意: 由于该程序不仅仅在Linux上运行,所以理想情况下我不希望使用像bash这样的东西。我也不想破坏其他程序。
答案 0 :(得分:0)
开发服务器在出错时不会重新启动,它只是处理异常并继续运行,就像生产服务器那样。这是它应该的方式 - HTTP是无状态的,一个请求中的错误不应该影响下一个请求。
所以你需要注意的是,无论你做什么,你可能会滥用runserver
,而且几乎肯定会有更好的方式这样做。
那说:
有几个地方阻止服务器在出错时退出。
首先,Django将每个请求包装在django.core.handlers.exception.convert_exception_to_response
函数中,该函数捕获每个Exception
并将其转换为良好的响应。因此,要通过此操作,您需要引发错误not derived from Exception
,例如KeyboardInterrupt
或SystemExit
。
然后有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)