Files
codex-app-server/cloud/tests/test_worker_quota.py
T
host ad014393ee worker: enforce quotas during execution (claim/retry/fallback/followup/poll kill)
- claim-time gate: queued task whose quota was spent while waiting is
  marked interrupted with a quota reason, no cost row, resume kept
- retry/fallback boundaries and every followup round check DB month
  usage plus this run's accumulated usage (priced via cost table)
- local popen poll loop kills the process group on quota (30s throttle);
  Docker/sync paths get boundary checks only (documented)
- quota stops finalize as interrupted + quota_exceeded error, keep the
  actual cost row, no push, followups restored to pending
2026-10-27 11:06:40 +08:00

249 lines
8.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""cloud worker 配额加固单测:认领门、后续消息执行时查配额、轮询掐断。
运行(在 ~/workspace/codex-app-server 下):
python3 -m unittest discover -s cloud/tests -p "test_worker_quota.py" -v
说明:只用注入的假 runner(假 CLI)与真 sleep 子进程,不跑真实
模型回合、不联网、不登录任何服务;env 映射也是注入的普通
dict,里面的值只是占位用的假名,绝不是真实密钥。
价目(cloud/cost.py,gpt-6.1-sol:input $2.00 / cached $0.10 /
output $10.00 每百万 token):input 10000 + output 1000 =
20000 + 10000 = 30000 微美元。配额 100000 微美元($0.10)。
"""
import json
import os
import sqlite3
import subprocess
import sys
import tempfile
import time
import unittest
from pathlib import Path
from types import SimpleNamespace
try:
from cloud.cost import CostStore
from cloud.server import init_db
from cloud.worker import Worker
except ImportError: # discover -s cloud/tests 时把项目根目录补进 sys.path
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.cost import CostStore
from cloud.server import init_db
from cloud.worker import Worker
QUOTA = 100000
def _insert_task(db_path, task_id, created_by="tester", status="queued",
project_id="p1"):
now = time.time()
conn = sqlite3.connect(db_path)
try:
conn.execute(
"INSERT INTO tasks(id, project_id, prompt, status,"
" idempotency_key, depends_on, priority, created_by,"
" created_at, updated_at, last_heartbeat)"
" VALUES(?, ?, ?, ?, NULL, '[]', 0, ?, ?, ?, NULL)",
(task_id, project_id, "do work", status, created_by, now, now),
)
conn.commit()
finally:
conn.close()
def _insert_quota(db_path, user_id, micros):
conn = sqlite3.connect(db_path)
try:
conn.execute(
"INSERT INTO user_quotas(user_id, quota_usd_micros, updated_at)"
" VALUES(?, ?, ?)",
(user_id, micros, time.time()),
)
conn.commit()
finally:
conn.close()
def _insert_donor_cost(db_path, micros):
"""给 tester 记一笔已花成本:另起一个已完成任务并记 actual 行。"""
_insert_task(db_path, "donor", status="completed")
store = CostStore(db_path)
try:
store.record("donor", "p1", "gpt-6.1-sol", input_tokens=1,
output_tokens=0, usd_micros=micros, 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)
try:
conn.execute(
"INSERT INTO task_followups(id, task_id, project_id, body,"
" mode, status, created_by, created_at, updated_at)"
" VALUES(?, ?, 'p1', ?, 'queued', 'pending', 'tester', ?, ?)",
(fu_id, task_id, body, now, now),
)
conn.commit()
finally:
conn.close()
def _status(db_path, task_id):
conn = sqlite3.connect(db_path)
try:
row = conn.execute(
"SELECT status FROM tasks WHERE id = ?", (task_id,)).fetchone()
finally:
conn.close()
return row[0] if row else None
def _error_text(db_path, task_id):
conn = sqlite3.connect(db_path)
try:
row = conn.execute(
"SELECT error_text FROM tasks WHERE id = ?",
(task_id,)).fetchone()
finally:
conn.close()
return row[0] if row else None
def _followup_status(db_path, fu_id):
conn = sqlite3.connect(db_path)
try:
row = conn.execute(
"SELECT status FROM task_followups WHERE id = ?",
(fu_id,)).fetchone()
finally:
conn.close()
return row[0] if row else None
def _cost_rows(db_path, task_id):
conn = sqlite3.connect(db_path)
try:
rows = conn.execute(
"SELECT usd_micros, source FROM cost_records"
" WHERE task_id = ?", (task_id,)).fetchall()
finally:
conn.close()
return rows
def _usage_runner(usage, calls):
"""假 CLI:dispatch/run 一律成功,stdout JSON 里带 usage。"""
def fake(cmd):
calls.append(list(cmd))
return SimpleNamespace(
returncode=0,
stdout=json.dumps({"status": "completed", "text": "done",
"usage": usage}),
stderr="")
return fake
class WorkerQuotaTestCase(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.db_path = os.path.join(self.tmp.name, "control.db")
init_db(self.db_path)
self.env = {"XCM_API_KEY": "test-placeholder"}
self.calls = []
def tearDown(self):
self.tmp.cleanup()
def _worker(self, runner):
return Worker(self.db_path, "/fake/host.py", runner=runner,
env=self.env, model="gpt-6.1-sol",
retry_backoff_seconds=0)
# -- 认领门 --------------------------------------------------------
def test_claim_time_quota_stop(self):
_insert_quota(self.db_path, "tester", QUOTA)
_insert_donor_cost(self.db_path, QUOTA)
_insert_task(self.db_path, "T1")
worker = self._worker(_usage_runner(
{"input_tokens": 10, "output_tokens": 1, "total_tokens": 11},
self.calls))
result = worker.run_one()
self.assertEqual(result["status"], "interrupted")
self.assertIn("quota_exceeded", result["error"])
self.assertEqual(_status(self.db_path, "T1"), "interrupted")
self.assertIn("quota_exceeded", _error_text(self.db_path, "T1"))
# 还没跑:runner 一次没调,也不记成本。
self.assertEqual(self.calls, [])
self.assertEqual(_cost_rows(self.db_path, "T1"), [])
# -- 后续消息执行时查配额 ------------------------------------------
def test_followup_quota_stop(self):
_insert_quota(self.db_path, "tester", QUOTA)
_insert_donor_cost(self.db_path, 90000)
_insert_task(self.db_path, "T1")
_insert_followup(self.db_path, "fu1", "T1")
# 首轮花 30000 微美元:90000 + 30000 = 120000 >= 100000,
# 排空时必须停,该条回 pending,任务 interrupted。
worker = self._worker(_usage_runner(
{"input_tokens": 10000, "cached_input_tokens": 0,
"output_tokens": 1000, "total_tokens": 11000},
self.calls))
result = worker.run_one()
self.assertEqual(result["status"], "interrupted")
self.assertIn("quota_exceeded", result["error"])
self.assertEqual(_status(self.db_path, "T1"), "interrupted")
self.assertEqual(_followup_status(self.db_path, "fu1"), "pending")
# 首轮只跑了一次(后续消息没跑),已花成本照记 actual。
self.assertEqual(len(self.calls), 1)
self.assertEqual(_cost_rows(self.db_path, "T1"),
[(30000, "actual")])
def test_followup_runs_when_under_quota(self):
_insert_quota(self.db_path, "tester", QUOTA)
_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))
result = worker.run_one()
self.assertEqual(result["status"], "completed")
self.assertEqual(_status(self.db_path, "T1"), "completed")
self.assertEqual(_followup_status(self.db_path, "fu1"), "done")
self.assertEqual(len(self.calls), 2)
def test_no_quota_row_is_unlimited(self):
_insert_task(self.db_path, "T1")
worker = self._worker(_usage_runner(
{"input_tokens": 100, "output_tokens": 10, "total_tokens": 110},
self.calls))
task = worker.get_task("T1")
self.assertIsNone(worker._quota_exceeded(task, None))
result = worker.run_one()
self.assertEqual(result["status"], "completed")
# -- 轮询掐断 ------------------------------------------------------
def test_poll_loop_quota_kill(self):
_insert_task(self.db_path, "T1")
worker = Worker(self.db_path, "/fake/host.py",
env=self.env, model="gpt-6.1-sol",
process_factory=lambda task: subprocess.Popen(
["sleep", "30"], start_new_session=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE))
task = worker.get_task("T1")
result = worker._execute_via_process(
task, kind="dispatch", quota_check=lambda: True)
self.assertEqual(result["status"], "quota_exceeded")
if __name__ == "__main__":
unittest.main()