Search code examples
pythonquart

Python Quart | Wait for create_task() to complete before exit


I have created an application using Quart, it has a background task that performs tasks such as data analysis and writing reports. When I end the application with ctrl-c the background thread is instantly killed, even if it's in the middle of an IO task, how do I get the framework to wait for the background task to finish please?

Update: My initial implementation was to use to have run() execute thread, I was trying to get away from this since asyncio supports the creation of tasks (create_task) and it seems like the better way, although I don't honestly know.

class Application:
    def __init__(self):
        self._is_initialised : bool = False
        self._shutdown_completed : bool = False
        self._shutdown_requested : bool = False

    async def run(self) -> None:
        while not self._shutdown_requested and self._is_initialised:
            try:
                await self._main_loop()
                await asyncio.sleep(0.1)

            except KeyboardInterrupt:
                break

        self._shutdown_completed = True

    def stop(self) -> None:
        print("Shutting down...")
        self._shutdown_requested = True
        print('Shutdown has completed')


import asyncio
from quart import Quart

app = Quart(__name__)
SERVICE_APP = None

@app.before_serving
async def startup() -> None:
    asyncio.create_task(SERVICE_APP.run())

@app.after_serving
async def shutdown() -> None:
    SERVICE_APP.stop()

SERVICE_APP = Application(app)

Solution

  • A background task is likely the better choice here as Quart will delay shutdown (for as long as the ASGI server allows) whilst waiting for the background tasks to stop, see docs:

    from quart import Quart
    
    app = Quart(__name__)
    
    async def background_task():
        # Actual code to run in the background
    
    @app.before_serving
    async def startup() -> None:
        app.add_background_task(background_task)