fix(db): await AsyncConnection.execution_options in run_maintenance
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 20s
CI & Build / Python tests (push) Successful in 48s
CI & Build / Build & push image (push) Successful in 1m0s

execution_options() is a coroutine on AsyncConnection and must be awaited;
the un-awaited call returned a coroutine, so exec_driver_sql() blew up with
AttributeError and every table's VACUUM was skipped (Run-now reported 0/6).
A prior change had wrongly dropped the await. Fix it and make the test mock
execution_options async so this call shape is actually exercised.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 18:31:30 -04:00
parent 96079d5b77
commit e6c89f6b88
2 changed files with 9 additions and 6 deletions
+4 -3
View File
@@ -66,9 +66,10 @@ async def run_maintenance(tables: tuple[str, ...] | list[str] | None = None) ->
results: list[dict] = []
async with engine.connect() as conn:
# execution_options() is synchronous on AsyncConnection; it returns the
# connection with AUTOCOMMIT set (VACUUM can't run in a transaction).
autocommit = conn.execution_options(isolation_level="AUTOCOMMIT")
# On AsyncConnection, execution_options() is a coroutine and MUST be
# awaited (it returns the connection with AUTOCOMMIT set VACUUM can't
# run inside a transaction block).
autocommit = await conn.execution_options(isolation_level="AUTOCOMMIT")
for table in targets:
t0 = time.monotonic()
try:
+5 -3
View File
@@ -16,7 +16,9 @@ def _mock_engine(exec_side_effect=None):
conn = MagicMock()
autocommit = MagicMock()
autocommit.exec_driver_sql = AsyncMock(side_effect=exec_side_effect)
conn.execution_options.return_value = autocommit # sync on AsyncConnection
# On AsyncConnection, execution_options() is a coroutine — mock it as async
# so the test exercises the real (awaited) call shape.
conn.execution_options = AsyncMock(return_value=autocommit)
cm = AsyncMock()
cm.__aenter__ = AsyncMock(return_value=conn)
cm.__aexit__ = AsyncMock(return_value=False)
@@ -36,9 +38,9 @@ async def test_vacuums_each_allowlisted_table_once():
assert issued == [f"VACUUM (ANALYZE) {t}" for t in MAINTENANCE_TABLES]
assert all(r["ok"] for r in summary["tables"])
assert len(summary["tables"]) == len(MAINTENANCE_TABLES)
# AUTOCOMMIT was requested — VACUUM cannot run inside a transaction.
# AUTOCOMMIT was requested (and awaited) — VACUUM can't run in a transaction.
conn = engine.connect.return_value.__aenter__.return_value
conn.execution_options.assert_called_once_with(isolation_level="AUTOCOMMIT")
conn.execution_options.assert_awaited_once_with(isolation_level="AUTOCOMMIT")
@pytest.mark.asyncio