Darren Oakey
Darren Oakey

Reputation: 3654

in python threadinghttpserver - stop server from inside handler

I have the following "main" code:

with  http.server.ThreadingHTTPServer( ("", port), Handler )  as daemon:
    print(f"serving on port {port} process {os.getpid()} ")
    while True:
        try:
            daemon.handle_request()
        except KeyboardInterrupt:
            print("\nexiting")
            return 0

which works great. However - this is only used for local testing and on the ci machine - so I want an easy way to shut it down and replace it with the next one - so inside the Handler do_GET(self) I added the following code:

   if path == "/shutdown":
       throw Exception("shut down")

and if I do a curl http://localhost:9000/shutdown.... I do indeed see an exception - nicely displayed and swallowed inside the thread.

And I've found it remarkably hard to figure out any way of stopping the server from inside the handler - because the handler is running in another process.

Is there a simple way of doing it?

Upvotes: 1

Views: 243

Answers (1)

You can spawn another thread and call the server's shutdown method, like so:

import http.server
import threading

from http import HTTPStatus


class Handler(http.server.SimpleHTTPRequestHandler):
    def do_STOP(self):
        # Make sure we send a valid response for the current request.
        # Here, we simply send a "204 No content" error response.
        self.send_error(HTTPStatus.NO_CONTENT)

        # This will send the shutdown signal to the server.
        # New requests will not be processed after that.
        threading.Thread(target=self.server.shutdown).start()


with http.server.ThreadingHTTPServer(("", 0), Handler) as httpd:
    print("Listening on port", httpd.server_address[1])
    httpd.serve_forever()

As noted in the source code for socketserver.BaseServer (of which ThreadingHTTPServer is a derived class), shutdown() must be called from a different thread to avoid a deadlock:

    def shutdown(self):
        """Stops the serve_forever loop.

        Blocks until the loop has finished. This must be called while
        serve_forever() is running in another thread, or it will
        deadlock.
        """

Upvotes: 0

Related Questions