fix(release): await new-api provisioning visibility

This commit is contained in:
lili 2026-07-23 00:04:34 -07:00
parent 94d35f0b97
commit b99f67f046
2 changed files with 29 additions and 2 deletions

View File

@ -235,6 +235,17 @@ def compute_grant(yuan: float, qpu: int, usd: float) -> int:
return round(yuan / usd * qpu)
def wait_for_db_visibility(query, attempts: int = 20, interval_seconds: float = 0.1):
"""等待 new-api API 写入在 PostgreSQL 可见;超出固定窗口后返回 None。"""
for attempt in range(attempts):
value = query()
if value is not None:
return value
if attempt + 1 < attempts:
time.sleep(interval_seconds)
return None
def validate_provision_request(start: int, count: int, prefix: str, hostname: str) -> list[str]:
"""校验离线补池边界,并返回确定性的目标用户名。
@ -279,7 +290,7 @@ def provision_one(pg: Postgres, root_token: str, username: str, grant: int,
"password": password,
"display_name": username[:20], # new-api DisplayName max=20直接用 username截断兜底
})
uid = pg.query_user_id(username)
uid = wait_for_db_visibility(lambda: pg.query_user_id(username))
if uid is None:
raise RuntimeError(f"建用户 {username} 后 postgres 未查到 uid")
log.info("[1/4] 建用户 %s → uid=%d", username, uid)
@ -304,7 +315,7 @@ def provision_one(pg: Postgres, root_token: str, username: str, grant: int,
"unlimited_quota": False,
"expired_time": -1, # 不过期,避免自伤式过期(设计 §3.9
})
tok = pg.query_token(uid, username)
tok = wait_for_db_visibility(lambda: pg.query_token(uid, username))
if tok is None:
raise RuntimeError(f"建 token 后 postgres 未查到 user={uid} name={username}")
log.info("[3/4] 建 token uid=%d → token_id=%d key=%s", uid, tok[0], _mask(tok[1]))

View File

@ -58,6 +58,22 @@ class ProvisionRequestTest(unittest.TestCase):
self.assertEqual(stat.S_IMODE(sql_path.stat().st_mode), 0o600)
self.assertIn("-- pool_entry username=neice_051 newapi_user_id=51", sql_path.read_text())
def test_waits_for_api_write_to_become_visible(self) -> None:
query = mock.Mock(side_effect=[None, None, 67])
with mock.patch.object(MODULE.time, "sleep") as sleep:
value = MODULE.wait_for_db_visibility(query, attempts=4, interval_seconds=0.1)
self.assertEqual(value, 67)
self.assertEqual(query.call_count, 3)
self.assertEqual(sleep.call_count, 2)
def test_db_visibility_wait_is_bounded(self) -> None:
query = mock.Mock(return_value=None)
with mock.patch.object(MODULE.time, "sleep") as sleep:
value = MODULE.wait_for_db_visibility(query, attempts=3, interval_seconds=0.1)
self.assertIsNone(value)
self.assertEqual(query.call_count, 3)
self.assertEqual(sleep.call_count, 2)
if __name__ == "__main__":
unittest.main()