简体   繁体   中英

How do I stop Django development server from restarting?

I want Django development server to exit when an error happens. But whenever the server exits, it restarts. I tried to kill the process using os.kill(os.getpid, 9) which does not work. I tried sys.exit, os._exit, and raised errors and none of them works.

Notes: Since the program doesn't only run on Linux, so ideally I wish not to use anything like bash. Also I don't want to disrupt other processes.

The development server doesn't restart on error, it just handles the exception and goes on, just as production server does. This is the way it's supposed to be – HTTP is stateless, error in one request shouldn't affect the next one.

So you need to be aware that whatever you're doing, you're probably abusing the runserver , and there's almost surely a better way to do it.

That said:

There are several places on which the server is prevented from exiting on error.

First, Django wraps each request in the django.core.handlers.exception.convert_exception_to_response function, which catches every Exception and turns it into a nice response. So to pass through this, you need to raise an error not derived from Exception , like a KeyboardInterrupt or a SystemExit .

Then there's django.core.servers.basehttp.ServerHandler , which derives from wsgiref.handers.BaseHandler , which wraps the request in a try: ... except: ... to catch all exceptions, and, again, turn them into responses. Since you probably still want to get that response, you'll have to modify the handle_error method to raise an error again after generating an error response.

Unfortunately, there's a lot of coupling there. The ServerHandler class is hard-coded into django.core.servers.basehttp.WSGIRequestHandler.handle , which is hard-coded into django.core.server.basehttp.run , which is hard-coded into django.core.management.commands.runserver . So you'd either have to copy all of that code (which is basically what Django does, copying some code from wsgiref ) or you're left with monkey-patching.

And then there's still django.core.servers.basehttp.WSGIServer , which is a subclass of socketserver.BaseServer . The exception we just re-raised now goes to WSGIServer.handle_error , which tries to turn it into a response and go on. So you need to override that.

Then it should work, provided you run the server without threads and auto-reloading, by running a custom command derived from runserver, as in:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM