Skip to content
Aabha AI Academy

Module 5 of 9 · Lesson 13 of 26

Convert database I/O to AsyncSession

Work through convert database I/O to AsyncSession using a runnable reference, a focused regression check and a local extension.

Read in any order. All lessons stay open, including after an unanswered or incorrect check.

In this lesson you will convert database I/O to AsyncSession. Work with the Equipment Rental API in the downloadable lab. The reference is a complete solution with separate lesson checks, so you can inspect the answer, make a deliberate local change and verify its behavior.
AsyncSession changes how database I/O is awaited, while the business invariant remains the same. reserve_async still locks equipment, reads active quantity, rejects insufficient capacity and inserts one rental within one transaction. execute, scalar, get and flush perform I/O and are awaited. Adding await at the boundary should preserve the response shape and error behavior of the synchronous service.

Create an asynchronous engine with an async-capable driver and an async_sessionmaker. Each request opens and closes its own AsyncSession. expire_on_commit=False helps the reference construct and return an already-loaded response without unexpected post-commit attribute I/O. Explicit eager loading is still necessary for relationships; a serializer must not accidentally try implicit async database work. Transaction completion precedes the success response just as it did synchronously. Convert one boundary at a time and compare behavior through the same contracts. An async rewrite is not permission to relax capacity checks, hide failures or share mutable session state across concurrently running tasks.
Worked source: equipment/services.py, reserve_async.

Compare reserve and reserve_async side by side. Run lesson13: the async service reserves one unit, rejects a subsequent request for two, and a separate synchronous session confirms only one active unit was committed. This cross-check verifies database visibility as well as the response model.
pythonCopyable
async def reserve_async(session, equipment_id, owner_id, quantity):
    if quantity < 1:
        raise DomainError("invalid_quantity", "Request at least one unit.", 422)
    async with session.begin():
        item = await session.scalar(
            select(Equipment).where(Equipment.id == equipment_id).with_for_update()
        )
        if item is None:
            raise missing()
        used = await session.scalar(
            select(func.coalesce(func.sum(Rental.quantity), 0)).where(
                Rental.equipment_id == equipment_id, Rental.status == "active"
            )
        )
        if used + quantity > item.quantity:
            raise DomainError(
                "capacity_unavailable", "Not enough equipment units are available."
            )
        rental = Rental(equipment_id=equipment_id, owner_id=owner_id, quantity=quantity)
        session.add(rental)
        await session.flush()
        result = RentalOut.model_validate(rental)
    return result
TerminalPython 3.13 virtual environment; Docker running; extracted lab directory
python run_checks.py -k lesson13

Expected result The selected lesson test passes against a new temporary PostgreSQL database; the container is removed afterward.

Keep for reference

Equipment Rental lab and lesson checks

ZIP containing Python source, real Alembic migrations, 26 lesson checks, a dependency lock and text instructions. Extract it before following the local exercise.

Download Equipment Rental lab and lesson checks

Practise locally

Port a read-only equipment lookup to AsyncSession in your own copy. Add success and missing-record tests, then compare their outputs with a synchronous implementation. Keep session ownership in the caller and await every database operation. Document which values are loaded before returning the response and why serialization cannot issue an unawaited query.

The lesson check verifies the reference behavior. Add your own assertions for your change. Local practice is not uploaded or scored by this learning release.

Pause and reflect

What failure does this lesson prevent, and which assertion in lesson13 would expose it?

Use a concrete input, expected result and limitation from your local work. Saving a reflection does not certify the project.

Optional knowledge check

What must stay unchanged when converting this reservation to async?

The capacity transaction, public response and deliberate failure contract.

Correct. Async changes I/O scheduling; it should preserve the business invariant and client behavior.

Only the function name; locking and rollback can be removed.

Try another answer. Removing the transaction protection changes correctness even if requests appear faster.

Return the ORM object and let lazy relationships load themselves later.

Try another answer. Implicit async I/O during serialization can fail; load the required data explicitly.

This practice does not assess your project or award a certificate.

Your reading progress

Progress is saved in this browser when storage is available.

Sign in to save across devices · Create an optional account