[Python] Werkzeug BaseWSGIServer Thread Hangs after Handling Request. Terminal Unresponsive

Discussão em 'Python' iniciado por Stack, Janeiro 26, 2025.

  1. Stack

    Stack Membro Participativo

    This has stopped me from doing anything useful for more than a week - if you have experience with Python/Werkzeug/Flask/Multi-threading, please help...

    Now, normally, you would run a Flask app in a separate terminal, via py flask.py, needing to manually spin it up and manually turn it off with Ctrl-C. My Python App only needs this local server in certain cases, for example: to get a token using Spotify's Authorization Code Flow so that I can later make valid requests using their Web API.

    My auth_server.py file is the "section" responsible for all of this. Here lives a Class named LocalServerThread, that subclasses Thread, taken word-for-word from this answer. 8 years ago, this was the only useful answer for Windows in a sea of shit; alas, unfortunately, today it is only a partially-working example.

    Here it is in it's full glory:

    from werkzeug.serving import make_server

    class ServerThread(threading.Thread):
    THREAD_NAME = 'LocalServerThread'

    def __init__(self, app):
    threading.Thread.__init__(self, name=LocalServerThread.THREAD_NAME)
    self.server = make_server('127.0.0.1', 8080, app)
    self.ctx = app.app_context()
    self.ctx.push()

    def run(self):
    log.info('starting server')
    self.server.serve_forever()

    def shutdown(self):
    self.server.shutdown()

    def start_server():
    global server
    app = flask.Flask('myapp')
    # App routes defined here
    server = ServerThread(app)
    server.start()
    log.info('server started')

    def stop_server():
    global server
    server.shutdown()


    Here is the rest of the code in question in my auth_server.py:

    def start_local_http_server():
    app = Flask(__name__)

    @app.route('/')
    def home():

    @app.route('/login')
    def login():

    @app.route('/callback')
    def callback():

    global server
    server = LocalServerThread(app)
    server.start()
    print(fr'Started {LocalServerThread.THREAD_NAME}, serving: http://127.0.0.1:8080')

    def stop_local_http_server():
    server.shutdown()


    Here is my actual code from main.py that is leveraging this code:

    if not auth_server.validate_token(reject=True):
    auth_server.start_local_http_server()

    time.sleep(4)

    auth_server.stop_local_http_server()

    print('Finally Done')


    Now here is where it all Falls Apart...
    I run it with py ./main.py. If I just let it run, shutdown will work perfectly, shutting everything down correctly. Good.
    However, if, while the main thread sleeps in those 4 seconds, I go to any of the routes ('/', '/login', '/callback'), and the server successfully serves me the page, then when the program reaches self.server.shutdown(), it will just hang around there anywhere from 90-300 seconds before finally exiting and reaching print('Finally Done') back in the main thread. During this time, the terminal will look like this, refusing to let the program exit: [​IMG]

    This is flippin' infuriating. I can't figure out what the heck is going in during debug as well. self.server.shutdown() goes deeper into socketserver.py BaseServer shutdown() method and I can't step into anything farther than the two lines within, like it's waiting around for something... But I got you the call stack:

    These are the Call Stacks side by side, right before the debug loses track of what's going on.
    First: Standard Run. ________________________ Second: going to '/' during the 4sec sleep:

    [​IMG] [​IMG]

    Note: One more time, I am on Windows.
    Is there anyone out there looking at this that has the knowledge/expertise to see the issue? This would really help not only me, but our posterity as well, I suspect...

    Continue reading...

Compartilhe esta Página