Bottle web framework - How to stop?

前端 未结 11 1230
不知归路
不知归路 2020-12-14 06:55

When starting a bottle webserver without a thread or a subprocess, there\'s no problem. To exit the bottle app -> CTRL + c.

In a thread, ho

相关标签:
11条回答
  • 2020-12-14 07:45

    This equally kludgy hack has the advantage that is doesn't have you copy-paste any code from bottle.py:

    # The global server instance.                                                                                             
    server = None
    
    def setup_monkey_patch_for_server_shutdown():
        """Setup globals to steal access to the server reference.                                                             
        This is required to initiate shutdown, unfortunately.                                                                 
        (Bottle could easily remedy that.)"""
    
        # Save the original function.                                                                                         
        from wsgiref.simple_server import make_server
    
        # Create a decorator that will save the server upon start.                                                            
        def stealing_make_server(*args, **kw):
            global server
            server = make_server(*args, **kw)
            return server
    
        # Patch up wsgiref itself with the decorated function.                                                                
        import wsgiref.simple_server
        wsgiref.simple_server.make_server = stealing_make_server
    
    setup_monkey_patch_for_server_shutdown()
    
    def shutdown():
        """Request for the server to shutdown."""
        server.shutdown()
    
    0 讨论(0)
  • 2020-12-14 07:47

    An updated version of mike's answer.

    from bottlepy.bottle import WSGIRefServer, run
    from threading import Thread
    import time
    
    class MyServer(WSGIRefServer):
        def run(self, app): # pragma: no cover
            from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
            from wsgiref.simple_server import make_server
            import socket
    
            class FixedHandler(WSGIRequestHandler):
                def address_string(self): # Prevent reverse DNS lookups please.
                    return self.client_address[0]
                def log_request(*args, **kw):
                    if not self.quiet:
                        return WSGIRequestHandler.log_request(*args, **kw)
    
            handler_cls = self.options.get('handler_class', FixedHandler)
            server_cls  = self.options.get('server_class', WSGIServer)
    
            if ':' in self.host: # Fix wsgiref for IPv6 addresses.
                if getattr(server_cls, 'address_family') == socket.AF_INET:
                    class server_cls(server_cls):
                        address_family = socket.AF_INET6
    
            srv = make_server(self.host, self.port, app, server_cls, handler_cls)
            self.srv = srv ### THIS IS THE ONLY CHANGE TO THE ORIGINAL CLASS METHOD!
            srv.serve_forever()
    
        def shutdown(self): ### ADD SHUTDOWN METHOD.
            self.srv.shutdown()
            # self.server.server_close()
    
    def begin():
        run(server=server)
    
    server = MyServer(host="localhost", port=8088)
    Thread(target=begin).start()
    time.sleep(2) # Shut down server after 2 seconds
    server.shutdown()
    

    The class WSGIRefServer is entirely copied with only 1 line added to the run() method is added. Also add a simple shutdown() method. Unfortunately, this is necessary because of the way bottle creates the run() method.

    0 讨论(0)
  • 2020-12-14 07:50

    I had trouble closing a bottle server from within a request as bottle seems to run requests in subprocesses.

    I eventually found the solution was to do:

    sys.stderr.close()
    

    inside the request (that got passed up to the bottle server and axed it).

    0 讨论(0)
  • 2020-12-14 07:50

    This is exactly the same method than sepero's and mike's answer, but now much simpler with Bottle version 0.13+:

    from bottle import W, run, route
    from threading import Thread
    import time
    
    @route('/')
    def index():
        return 'Hello world'
    
    def shutdown():
        time.sleep(5)
        server.srv.shutdown()
    
    server = WSGIRefServer(port=80)
    Thread(target=shutdown).start()
    run(server=server)
    

    Also related: https://github.com/bottlepy/bottle/issues/1229 and https://github.com/bottlepy/bottle/issues/1230.


    Another example with a route http://localhost/stop to do the shutdown:

    from bottle import WSGIRefServer, run, route
    from threading import Thread
    
    @route('/')
    def index():
        return 'Hello world'
    
    @route('/stop')
    def stopit():
        Thread(target=shutdown).start()
    
    def shutdown():
        server.srv.shutdown()
    
    server = WSGIRefServer(port=80)
    run(server=server)
    

    PS: it requires at least Bottle 0.13dev.

    0 讨论(0)
  • 2020-12-14 07:50

    I've found this solution to be the easiest, but it does require that the "psutil" package is installed, to get the current process. It also requires the "signals" module, but that's part of the standard library.

    @route('/shutdown')
    def shutdown():
        current_process = psutil.Process()
        current_process.send_signal(signal.CTRL_C_EVENT)
        return 'Shutting down the web server'
    

    Hope that's of use to someone!

    0 讨论(0)
提交回复
热议问题