Reuse the database a borrowed client already holds
`clients_for` hands back a client over a database the covering one owns, so `async with` on it opened a second session and assigned it, and teardown declined to close what this client did not open. Entry returns the client as it stands.
This commit is contained in:
parent
de8075fcd1
commit
2b2de5a61f
2 changed files with 33 additions and 0 deletions
|
|
@ -295,11 +295,19 @@ class HaikuRAG:
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
"""Async context manager entry — initializes store and repositories.
|
"""Async context manager entry — initializes store and repositories.
|
||||||
|
|
||||||
|
A client borrowing a database is already open and returns itself.
|
||||||
|
Opening a second session would leak it: teardown declines to close what
|
||||||
|
this client did not open.
|
||||||
|
|
||||||
A client covering several databases opens none of them here: which are
|
A client covering several databases opens none of them here: which are
|
||||||
searched is a per-query choice, so they open on first use. `store` and the
|
searched is a per-query choice, so they open on first use. `store` and the
|
||||||
repositories stay unset in that case, since they have no unambiguous
|
repositories stay unset in that case, since they have no unambiguous
|
||||||
meaning across a set.
|
meaning across a set.
|
||||||
"""
|
"""
|
||||||
|
if not self._owns_session:
|
||||||
|
assert self._session is not None
|
||||||
|
return self
|
||||||
|
|
||||||
scope = self._resolve_scope()
|
scope = self._resolve_scope()
|
||||||
if scope.covers_multiple:
|
if scope.covers_multiple:
|
||||||
if self._create:
|
if self._create:
|
||||||
|
|
@ -338,6 +346,10 @@ class HaikuRAG:
|
||||||
Opening is per query rather than at entry: a set of 25 configured
|
Opening is per query rather than at entry: a set of 25 configured
|
||||||
databases is typically queried a few at a time, and a database nobody
|
databases is typically queried a few at a time, and a database nobody
|
||||||
asked for must not be able to fail a query, or be opened for nothing.
|
asked for must not be able to fail a query, or be opened for nothing.
|
||||||
|
|
||||||
|
The clients returned borrow their databases from this one and are valid
|
||||||
|
only while it is open. Closing one, or entering it as a context manager,
|
||||||
|
leaves the database alone; this client closes them all on teardown.
|
||||||
"""
|
"""
|
||||||
assert isinstance(self._session, FederatedSession)
|
assert isinstance(self._session, FederatedSession)
|
||||||
names = _without_repeats(names)
|
names = _without_repeats(names)
|
||||||
|
|
|
||||||
|
|
@ -598,6 +598,27 @@ class TestBorrowedDatabases:
|
||||||
assert {r.source for r in results} == {"alpha", "beta"}
|
assert {r.source for r in results} == {"alpha", "beta"}
|
||||||
assert not store.db.is_open(), "the set left a database open"
|
assert not store.db.is_open(), "the set left a database open"
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_entering_a_borrowed_client_reuses_its_database(self, tmp_path):
|
||||||
|
"""`async with` on a borrowed client is a plausible thing to write.
|
||||||
|
Opening a second session would leak it, since teardown declines to close
|
||||||
|
what this client did not open."""
|
||||||
|
config = _config(tmp_path, ["alpha", "beta"])
|
||||||
|
await _seed(config, "alpha", ["alpha document about cats"])
|
||||||
|
|
||||||
|
async with HaikuRAG(config=config) as rag:
|
||||||
|
(alpha,) = await rag.clients_for(["alpha"])
|
||||||
|
borrowed = alpha.store
|
||||||
|
|
||||||
|
async with alpha as entered:
|
||||||
|
assert entered is alpha
|
||||||
|
assert alpha.store is borrowed, "entry opened a second database"
|
||||||
|
|
||||||
|
assert borrowed.db.is_open(), "exit closed a database it borrowed"
|
||||||
|
assert alpha.store is borrowed
|
||||||
|
|
||||||
|
assert not borrowed.db.is_open(), "the set left a database open"
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_a_borrowed_client_releases_what_it_built(self, tmp_path):
|
async def test_a_borrowed_client_releases_what_it_built(self, tmp_path):
|
||||||
"""Its reranker is its own; the database it wraps is not."""
|
"""Its reranker is its own; the database it wraps is not."""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue