fix: keep the postgres backfill from disabling telemetry or locking the table
This commit is contained in:
@@ -219,6 +219,78 @@ class TestSQLiteColumnBackfill:
|
||||
recorder.close()
|
||||
|
||||
|
||||
class _FakePgConn:
|
||||
"""记录执行过的语句;可让 ALTER 抛错以模拟权限不足。"""
|
||||
|
||||
def __init__(self, existing: list[str], *, fail_alter: bool = False):
|
||||
self.existing = existing
|
||||
self.fail_alter = fail_alter
|
||||
self.statements: list[str] = []
|
||||
|
||||
async def execute(self, sql, *args):
|
||||
self.statements.append(sql)
|
||||
if sql.startswith("ALTER TABLE") and self.fail_alter:
|
||||
raise RuntimeError("must be owner of table llm_calls")
|
||||
|
||||
async def fetch(self, sql, *args):
|
||||
self.statements.append(sql)
|
||||
return [{"attname": name} for name in self.existing]
|
||||
|
||||
|
||||
class _FakePgPool:
|
||||
def __init__(self, conn):
|
||||
self._conn = conn
|
||||
|
||||
def acquire(self):
|
||||
conn = self._conn
|
||||
|
||||
class _Ctx:
|
||||
async def __aenter__(self):
|
||||
return conn
|
||||
|
||||
async def __aexit__(self, *exc):
|
||||
return False
|
||||
|
||||
return _Ctx()
|
||||
|
||||
|
||||
class TestPostgresBackfillDiscipline:
|
||||
"""PG 补列必须与 SQLite 侧对称: 失败只逐行降级,且稳态不抢排他锁(issue #3)。"""
|
||||
|
||||
_LEGACY = ["call_id", "cost", "created_at"]
|
||||
_CURRENT = ["call_id", "cost", "created_at", "cached_prompt_tokens", "model_reported"]
|
||||
|
||||
def _recorder(self, conn):
|
||||
from polygateway.telemetry.postgres import PostgresRecorder
|
||||
|
||||
return PostgresRecorder("postgresql://u:p@h:5432/polygateway", pool=_FakePgPool(conn))
|
||||
|
||||
async def test_alter_failure_does_not_disable_the_recorder(self):
|
||||
"""ALTER 失败(如账号只有 INSERT 权限)不得置 _failed —— 那会让遥测全灭。"""
|
||||
conn = _FakePgConn(self._LEGACY, fail_alter=True)
|
||||
recorder = self._recorder(conn)
|
||||
await _record_minimal(recorder) # 不得抛
|
||||
assert recorder._failed is False
|
||||
assert any(s.startswith("INSERT INTO llm_calls") for s in conn.statements)
|
||||
|
||||
async def test_no_alter_when_columns_already_exist(self):
|
||||
"""ADD COLUMN IF NOT EXISTS 即使列已存在也会先抢 ACCESS EXCLUSIVE 锁,
|
||||
|
||||
而遥测是内联 await——稳态下必须一条 ALTER 都不发,否则每个进程的首次
|
||||
写入都会去锁共享审计表。
|
||||
"""
|
||||
conn = _FakePgConn(self._CURRENT)
|
||||
await _record_minimal(self._recorder(conn))
|
||||
assert not [s for s in conn.statements if s.startswith("ALTER TABLE")]
|
||||
|
||||
async def test_missing_columns_are_added_once(self):
|
||||
conn = _FakePgConn(self._LEGACY)
|
||||
await _record_minimal(self._recorder(conn))
|
||||
altered = [s for s in conn.statements if s.startswith("ALTER TABLE")]
|
||||
assert len(altered) == 2
|
||||
assert all("IF NOT EXISTS" not in s for s in altered) # 探测已确认缺列,无需再判
|
||||
|
||||
|
||||
class _MemoryRecorder:
|
||||
def __init__(self):
|
||||
self.rows = []
|
||||
|
||||
Reference in New Issue
Block a user