.. _startup_shutdown:

Startup and Shutdown
====================

The `ASGI lifespan specification`_ includes the ability for awaiting
coroutines before the first byte is received and after the final byte
is sent, through the ``startup`` and ``shutdown`` lifespan events.
This is particularly useful for creating and destroying connection
pools.  Quart supports this via the decorators
:func:`~quart.app.Quart.before_serving` and
:func:`~quart.app.Quart.after_serving`, which function like
:func:`~quart.app.Quart.before_first_request`.

.. _ASGI lifespan specification: https://github.com/django/asgiref/blob/master/specs/lifespan.rst

The decorated functions are all called within the app context,
allowing ``current_app`` and ``g`` to be used.

To use this functionality simply do the following:

.. code-block:: python

    @app.before_serving
    async def create_db_pool():
        app.db_pool = await ...
        g.something = something

    @app.before_serving
    async def use_g():
        g.something.do_something()

    @app.route("/")
    async def index():
        app.db_pool.execute(...)
        g.something.do_something_else()

    @app.after_serving
    async def create_db_pool():
        await app.db_pool.close()

Testing
-------

Quart's test client works on a request lifespan and hence does not
call ``before_serving`` or ``after_serving`` functions. Instead
Quart's test app can be used, for example

.. code-block:: python

    @pytest.fixture(name="app", scope="function")
    async def _app():
        app = create_app()  # Initialize app
        async with app.test_app() as test_app:
            yield test_app

The app fixture can then be used as normal, knowing that the
``before_serving`` and ``after_serving`` functions have been called,

.. code-block:: python

    @pytest.mark.asyncio
    async def test_index(app):
        test_client = app.test_client()
        await test_client.get("/")
        ...
