Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
388 views
in Technique[技术] by (71.8m points)

multithreading - Python Quart Unable to shutdown background task

I am working on a Python app, but I am moving from Flask to Quart. The application needs a background task that runs constantly whilst the application is running.

When I try to stop the process using control-c, the thread doesn't close cleanly and sits in the while loop in the shutdown routine.

    while not self._master_thread_class.shutdown_completed:
        if not pro:
            print('[DEBUG] Thread is not complete')
            pro = True

I have followed this Stackoverflow question, but I can't figure out how to cleanly shutdown the background thread so I would love an explanation please as it seems like the Quart Documentation is lacking a bit.

MasterThread class:

import asyncio

class MasterThread:

    def __init__(self, shutdown_requested_event):
        self._shutdown_completed = False
        self._shutdown_requested_event = shutdown_requested_event
        self._shutdown_requested = False

    def __del__(self):
        print('Thread was deleted')

    def run(self, loop) -> None:
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self._async_entrypoint())

    @asyncio.coroutine
    def _async_entrypoint(self) -> None:
        while not self. _shutdown_requested and 
            not self._shutdown_requested_event.isSet():
            #print('_main_loop()')
            pass

            if self._shutdown_requested_event.wait(0.1):
                self. _shutdown_requested = True

        print('[DEBUG] thread has completed....')
        self._shutdown_completed = True

    def _main_loop(self) -> None:
        print('_main_loop()')

Main application module:

import asyncio
import threading
from quart import Quart
from workthr import MasterThread

app = Quart(__name__)

class Service:

    def __init__(self):
        self._shutdown_thread_event = threading.Event()
        self._master_thread = MasterThread(self._shutdown_thread_event)
        self._thread = None

    def __del__(self):
        self.stop()

    def start(self):
        loop = asyncio.get_event_loop()
        self._thread = threading.Thread(target=self._master_thread.run, args=(loop,))
        self._thread.start()
        return True

    def stop(self) -> None:
        print('[DEBUG] Stop signal caught...')
        self._shutdown_thread_event.set()
        while not self._master_thread.shutdown_completed:
            print('[DEBUG] Thread is not complete')

        print('[DEBUG] Thread has completed')

        self._shutdown()

    def _shutdown(self):
        print('Shutting down...')

service = Service()
service.start()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Quart has startup and shutdown methods that allow something to be started before the server starts serving and stopped when the server finishes serving. If your background task is mostly IO bound I'd recommend just using a coroutine function rather than a thread,

async def background_task():
    while True:
        ...

@app.before_serving
async def startup():
    app.background_task = asyncio.ensure_future(background_task())

@app.after_serving
async def shutdown():
    app.background_task.cancel()  # Or use a variable in the while loop

Or you can do the same with your Service,

@app.before_serving
async def startup():
    service.start()

@app.after_serving
async def shutdown():
    service.stop()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...