Mongodb Motor committing session even when i did not explicitly commit

I don’t understand what going on,I have done exactly what the docs says.
In my app you would see i have two files, main and database, I defined dd() in main which I passed to do_transactions.

The problems

  • 1: The transaction is committed even when that line of code was never executed, query returned None.
  • 2: The transaction is still committed when await session.commit_transaction() is removed or commented, query returned None.

when I comment/removed callback() the transaction does not get committed, what could be the problem?

main.py

import asyncio
from motor.motor_asyncio import AsyncIOMotorDatabase

async def test():
    from .database import do_transactions
    async def dd(database: AsyncIOMotorDatabase) -> int:
        comments_collection = database.get_collection("comments")
        test_collection = database.get_collection("test")
        await test_collection.delete_many({})
        await comments_collection.insert_one({"name": "test"})

        return 449

    query = await do_transactions(dd, bool)
    pprint(query)


if __name__ == "__main__":
    asyncio.run(test())

database.py

from motor.motor_asyncio import (
    AsyncIOMotorClient,
    AsyncIOMotorCollection,
    AsyncIOMotorDatabase,
    AsyncIOMotorClientSession,
)
T = TypeVar("T")
async def do_transactions(
    self,
    callback: Callable[[AsyncIOMotorDatabase], Coroutine[Any, Any, T]],
    return_type: Type[T],
) -> T | None:
    client=AsyncIOMotorClient("uri")

    async with await client.start_session() as session:
        db = session.client.get_database(name="database")
        try:
            async with session.start_transaction():
                result = 777 # this works fine
                #result = await callback(db) transaction will be committed if this is uncommented
                if not isinstance(result, return_type):
                    await session.abort_transaction()
                    return None
                await session.commit_transaction() # removing this still commits the transaction if callback() is uncommented
                await session.end_session()
                return result
        except Exception as e:
            await session.abort_transaction()
            return None
1 Like

session.start_transaction() is a context manager which automatically commits the transaction if the with-block completes without raising an exception. The motor docs don’t explain this well: AsyncIOMotorClientSession – Sequence of operations — Motor 3.5.1 documentation

But the pymongo docs do explain it, here: client_session – Logical sessions for sequential operations - PyMongo 4.9.0.dev0 documentation

Upon normal completion of with session.start_transaction() block, the transaction automatically calls ClientSession.commit_transaction(). If the block exits with an exception, the transaction automatically calls ClientSession.abort_transaction().

1 Like