fix(storage): address review on PR #799 (stale comments, docs deprecation, unit test)

claude-review on #799 flagged:

1. Stale inline comment in ``initialize()`` (line 466) still said
   "Postgres uses a small bounded pool". Updated to reflect both
   backends now use NullPool.

2. Stale ``close()`` docstring referenced pool-size starving
   max_connections — irrelevant with NullPool. Replaced with the
   NullPool-aware rationale (dispose still tears down in-flight
   asyncpg connections cleanly).

3. ``docs/configuration.md`` actively directed operators to tune
   DATABASE_POOL_SIZE / DATABASE_MAX_OVERFLOW, with worked
   examples and pool math. Both are now deprecated no-ops; the
   table entries explain the deprecation and link to PR #799.
   Operators reading the docs will no longer be confused into
   tuning settings that don't do anything.

4. ``config.py`` comment for the deprecated fields updated to
   record the deprecation. Validators are intentionally kept
   (still reject < 1 / < 0) so misconfigured deploys fail loudly
   rather than silently — the reviewer flagged this as a minor
   UX wart but explicitly "not a blocker"; the docs change in (3)
   keeps operators away from the config altogether.

5. New ``tests/unit/test_storage_engine.py`` with three tests:
   - ``test_postgres_engine_uses_nullpool`` — pins ``isinstance(
     engine.pool, NullPool)`` so a refactor back to QueuePool /
     SingletonThreadPool can't silently re-introduce the cross-
     event-loop crashes.
   - ``test_postgres_engine_ignores_pool_sizing_settings`` —
     setting DATABASE_POOL_SIZE / DATABASE_MAX_OVERFLOW to huge
     values must not change pool type (proves the deprecated
     fields are wired-up no-ops).
   - ``test_postgres_engine_missing_asyncpg_driver_message`` —
     guards the existing actionable-error branch when the
     optional ``[postgres]`` extra isn't installed.

Verified:
- ``uv run pytest tests/unit/`` — 1028 passed
- ``uv run ruff check`` clean on the touched python files

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-17 18:45:14 +02:00
co-authored by Claude Opus 4.7
parent 8cd3092e87
commit e98903c502
4 changed files with 114 additions and 24 deletions
+10 -10
View File
@@ -463,10 +463,11 @@ class RefreshTokenStorage:
if Path(self.db_path).exists():
os.chmod(self.db_path, 0o600)
# Create the shared async engine for the chosen backend. SQLite uses
# NullPool (per-call connections, matches the prior aiosqlite-direct
# behavior); Postgres uses a small bounded pool — see
# ``_build_postgres_engine`` for sizing rationale.
# Create the shared async engine for the chosen backend. Both
# SQLite and Postgres use NullPool (per-call connections, no
# cross-loop bookkeeping). SQLite mirrors the prior
# aiosqlite-direct behavior; see ``_build_postgres_engine`` for
# the Postgres rationale.
if is_sqlite:
self.engine = create_async_engine(
self.database_url,
@@ -598,12 +599,11 @@ class RefreshTokenStorage:
async def close(self) -> None:
"""Dispose the underlying AsyncEngine on shutdown.
Without an explicit dispose, asyncpg's pooled connections leak
server-side slots until the Postgres
``idle_in_transaction_session_timeout`` reaps them — with the
small pool defaults and frequent k8s rolling restarts this can
starve ``max_connections``. Idempotent: safe to call from any
number of shutdown hooks.
With ``NullPool`` the dispose call has no idle pool to drain,
but it still cleanly tears down any in-flight asyncpg
connections held by active checkouts so shutdown hooks don't
leave dangling transports behind. Idempotent: safe to call
from any number of shutdown hooks.
"""
if self.engine is None:
return