多用户生产级缺口批:sweep 鉴权、默认配额、默认 executor、 无价 token 上限

- POST /admin/sweep 改走任一项目 maintainer+ 门槛(与备份管理同口径),否则 403,记 admin_sweep 审计;threshold 下限钳 60 秒
- OAuth 建号 created=True 时写默认配额行(默认 $10/月,CLOUD_DEFAULT_QUOTA_USD_MICROS 可调,INSERT OR IGNORE 幂等);老用户无配额行不受影响
- 建任务未指定且无环境继承时默认 executor=docker(分支继承为空时同理);CLOUD_DEFAULT_EXECUTOR 可覆盖,空字符串恢复旧行为;命令台下拉默认改为 docker
- 无价模型 token 上限:价目表外模型(默认 terra)成本 usd 为 NULL,USD 配额永不生效;有配额行的用户当月无价 token 达 CLOUD_QUOTA_UNPRICED_TOKEN_CAP(默认 2000 万/月)即停,服务端 402、worker 认领/重试/后续消息同口径;报表仍记 unpriced,不折假美元
- 测试:新增 test_multiuser_gaps 11 个 + test_worker_quota 3 个;全量 cloud 668、host 64、deploy 19 全过
This commit is contained in:
host committed 2026-10-27 17:15:09 +08:00
1 parent c1f9313c10
commit 7e081211db
7 files changed
+580 -13

No files matched your search

+87
View File
@@ -80,6 +80,26 @@ def _insert_donor_cost(db_path, micros):
pass
def _insert_unpriced_cost(db_path, tokens):
"""给 tester 记一笔无价成本:已完成任务 + usd_micros NULL 的行。
tokens 拆成 input/output 两半记(input + output = tokens,
与服务端/ worker 的无价 token 口径一致)。
"""
_insert_task(db_path, "donor-unpriced", status="completed")
store = CostStore(db_path)
try:
store.record("donor-unpriced", "p1", "gpt-5.6-terra",
input_tokens=tokens // 2,
output_tokens=tokens - tokens // 2,
usd_micros=None, source="actual")
finally:
try:
store._conn.close()
except Exception:
pass
def _insert_followup(db_path, fu_id, task_id, body="follow up"):
now = time.time()
conn = sqlite3.connect(db_path)
@@ -229,6 +249,73 @@ class WorkerQuotaTestCase(unittest.TestCase):
result = worker.run_one()
self.assertEqual(result["status"], "completed")
# -- 无价 token 上限 -------------------------------------------------
def test_unpriced_token_cap_blocks_claim(self):
_insert_quota(self.db_path, "tester", 10 ** 12) # USD 很大,不挡
_insert_unpriced_cost(self.db_path, 150)
_insert_task(self.db_path, "T1")
worker = self._worker(_usage_runner(
{"input_tokens": 10, "output_tokens": 1, "total_tokens": 11},
self.calls))
old = os.environ.get("CLOUD_QUOTA_UNPRICED_TOKEN_CAP")
os.environ["CLOUD_QUOTA_UNPRICED_TOKEN_CAP"] = "100"
try:
result = worker.run_one()
finally:
if old is None:
os.environ.pop("CLOUD_QUOTA_UNPRICED_TOKEN_CAP", None)
else:
os.environ["CLOUD_QUOTA_UNPRICED_TOKEN_CAP"] = old
self.assertEqual(result["status"], "interrupted")
self.assertIn("无价模型 token", result["error"])
self.assertEqual(self.calls, [])
def test_unpriced_round_usage_counts_toward_cap(self):
_insert_quota(self.db_path, "tester", 10 ** 12)
_insert_unpriced_cost(self.db_path, 90)
_insert_task(self.db_path, "T1")
_insert_followup(self.db_path, "fu1", "T1")
worker = Worker(self.db_path, "/fake/host.py", runner=_usage_runner(
{"input_tokens": 50, "cached_input_tokens": 0,
"output_tokens": 0, "total_tokens": 50},
self.calls), env=self.env, model="gpt-5.6-terra",
retry_backoff_seconds=0)
old = os.environ.get("CLOUD_QUOTA_UNPRICED_TOKEN_CAP")
os.environ["CLOUD_QUOTA_UNPRICED_TOKEN_CAP"] = "100"
try:
result = worker.run_one()
finally:
if old is None:
os.environ.pop("CLOUD_QUOTA_UNPRICED_TOKEN_CAP", None)
else:
os.environ["CLOUD_QUOTA_UNPRICED_TOKEN_CAP"] = old
# 首轮无价 50 token:90 + 50 = 140 >= 100,排空时停。
self.assertEqual(result["status"], "interrupted")
self.assertIn("quota_exceeded", result["error"])
self.assertEqual(_followup_status(self.db_path, "fu1"), "pending")
def test_priced_usage_ignores_token_cap(self):
_insert_quota(self.db_path, "tester", 10 ** 12)
_insert_unpriced_cost(self.db_path, 90)
_insert_task(self.db_path, "T1")
_insert_followup(self.db_path, "fu1", "T1")
worker = self._worker(_usage_runner(
{"input_tokens": 100, "cached_input_tokens": 0,
"output_tokens": 10, "total_tokens": 110},
self.calls))
old = os.environ.get("CLOUD_QUOTA_UNPRICED_TOKEN_CAP")
os.environ["CLOUD_QUOTA_UNPRICED_TOKEN_CAP"] = "100"
try:
result = worker.run_one()
finally:
if old is None:
os.environ.pop("CLOUD_QUOTA_UNPRICED_TOKEN_CAP", None)
else:
os.environ["CLOUD_QUOTA_UNPRICED_TOKEN_CAP"] = old
# 有价模型用量不计入无价上限:90 < 100,正常跑完。
self.assertEqual(result["status"], "completed")
self.assertEqual(_followup_status(self.db_path, "fu1"), "done")
# -- 轮询掐断 ------------------------------------------------------
def test_poll_loop_quota_kill(self):
_insert_task(self.db_path, "T1")