Opt-in shared-session Mongo backend composition; not a public mutation fence.
One domain owns its newly constructed client. Transactions are single-task,
never replay their body, and refuse unsupported topology and operations.
Unknown commit outcomes block subsequent transactions pending reconciliation.
MongoSessionDomain
MongoSessionDomain(uri: str, database: str = 'symfonic', *, collection_prefix: str = 'graph', collection: str = 'vectors')
Own a graph/vector pair whose collection operations share one session.
Creation is lazy. The extra lazy vector client is newly created here and
closed before any use; existing externally owned clients are never rebound.
This domain is an explicit backend prerequisite, not HMS admission.
Source code in src/symfonic/memory/backends/mongo_session.py
| def __init__(self, uri: str, database: str = "symfonic", *,
collection_prefix: str = "graph", collection: str = "vectors") -> None:
from symfonic.memory.backends.mongodb import MongoGraphBackend, MongoVectorBackend
self.graph = MongoGraphBackend(uri, database, collection_prefix)
try:
self.vector = MongoVectorBackend(uri, database, collection)
except BaseException:
self.graph._client.close()
raise
self.vector._client.close()
self._client = self.graph._client
self.vector._client = self._client
self._owner = None
self._session = None
self._closed = False
self._uncertain = False
shared_database = self._client[database]
self.graph._db = _Database(shared_database, self)
self.vector._db = self.graph._db
self.vector._col = self.vector._db[collection]
self._database = self.graph._db
self._vector_collection = self.vector._col
|
close
Close only this domain's client; active transactions must exit first.
Source code in src/symfonic/memory/backends/mongo_session.py
| def close(self) -> None:
"""Close only this domain's client; active transactions must exit first."""
if self._owner is not None:
raise MongoSessionError("Cannot close an active transaction")
self._closed = True
self._client.close()
|
transaction
async
Settle I/O before abort; commit cancellation requires reconciliation.
Source code in src/symfonic/memory/backends/mongo_session.py
| @asynccontextmanager
async def transaction(self):
"""Settle I/O before abort; commit cancellation requires reconciliation."""
try:
from pymongo.read_concern import ReadConcern
from pymongo.write_concern import WriteConcern
except ImportError as exc:
raise ImportError(
"Mongo sessions require pymongo. Install: pip install symfonic-core[mongodb]"
) from exc
if self._uncertain:
raise MongoSessionError("Unknown commit outcome; reconcile before using a new domain")
if self._closed or self._owner is not None:
raise MongoSessionError("Closed, nested, or concurrent transaction")
if self.graph._client is not self._client or self.vector._client is not self._client:
raise MongoSessionError("Backends no longer share the owned client")
if (self.graph._db is not self._database or self.vector._db is not self._database
or self.vector._col is not self._vector_collection):
raise MongoSessionError("Backends no longer use enlisted collection boundaries")
self._owner = asyncio.current_task()
try:
hello = await self._client.admin.command("hello")
if (not hello.get("setName") and hello.get("msg") != "isdbgrid") or (
hello.get("logicalSessionTimeoutMinutes") is None
):
raise MongoSessionError("Mongo transactions require replica set or mongos sessions")
opened = await _settle(
self._client.start_session(),
cancelled_result=lambda session: session.end_session(),
)
async with opened as session:
self._session = session
session.start_transaction(
read_concern=ReadConcern("snapshot"), write_concern=WriteConcern("majority"),
)
try:
yield self
except BaseException:
try:
await _settle(session.abort_transaction())
except BaseException:
self._uncertain = True
raise
raise
else:
try:
await _settle(session.commit_transaction())
except BaseException:
self._uncertain = True
raise
except Exception as exc:
label = getattr(exc, "has_error_label", None)
if callable(label) and label("UnknownTransactionCommitResult"):
self._uncertain = True
raise
finally:
self._session = None
self._owner = None
|
MongoSessionError
Bases: RuntimeError
An operation cannot participate in the current Mongo transaction.