Files
DadaoTask/backend/scripts/bench_views.py
T
dadao c4868f04cf feat(task): 批量改状态与看板数据接口
- POST /items/batch-status:逐条成败,不做全回滚;拖 10 条里 1 条冲突不该让另 9 条白干
- GET /items/board:四列一次取全,收件箱不进看板
- 修:/items/board 被 /{item_id} 抢先匹配导致 422
- 新增向量库配置项(M3 用,独立实例,不动 fnsvr-01)
- 3 个新测试,全量 46 passed
2026-10-28 04:05:35 +08:00

91 lines
3.6 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.
"""四视图 + 看板的首屏耗时实测(1000 条任务)。
不是压测工具,只回答一个问题:**1000 条之后,点开还会不会卡**。
跑之前先起后端:`uvicorn app.main:app --port 8100`(连开发库)。
python scripts/bench_views.py
"""
from __future__ import annotations
import asyncio
import statistics
import time
import uuid
from datetime import datetime, timedelta, timezone
import httpx
BASE = "http://127.0.0.1:8100/api/v1"
TOTAL = 1000
REPEAT = 15
async def login(client: httpx.AsyncClient) -> tuple[str, dict[str, str]]:
phone = f"137{uuid.uuid4().int % 100_000_000:08d}"
sent = await client.post(f"{BASE}/auth/sms/send", json={"phone": phone})
code = sent.json()["data"]["dev_code"]
out = await client.post(f"{BASE}/auth/login", json={"phone": phone, "code": code})
token = out.json()["data"]["tokens"]["access_token"]
return token, {"Authorization": f"Bearer {token}"}
async def main() -> None:
async with httpx.AsyncClient(timeout=30.0) as client:
_, headers = await login(client)
ws = await client.post(f"{BASE}/workspaces", json={"name": "性能实测"}, headers=headers)
ws_id = ws.json()["data"]["id"]
now = datetime.now(timezone.utc)
statuses = ["todo", "doing", "blocked", "done", "inbox"]
print(f"造 {TOTAL} 条任务……")
started = time.perf_counter()
for index in range(TOTAL):
payload = {
"title": f"测试任务 {index:04d} " + ("周报" if index % 7 == 0 else "跟进"),
"status": statuses[index % len(statuses)],
"priority": index % 4,
"due_at": (now + timedelta(days=(index % 10) - 5)).isoformat(),
"tag_names": ["批量", f"组{index % 5}"],
}
await client.post(f"{BASE}/workspaces/{ws_id}/items", json=payload, headers=headers)
print(f"写入耗时 {time.perf_counter() - started:.1f}s")
targets = {
"今天": f"/workspaces/{ws_id}/items?view=today&limit=30",
"进行中": f"/workspaces/{ws_id}/items?view=active&limit=30",
"收件箱": f"/workspaces/{ws_id}/items?view=inbox&limit=30",
"全部": f"/workspaces/{ws_id}/items?view=all&limit=30",
"搜索(周报)": f"/workspaces/{ws_id}/items?view=all&q=%E5%91%A8%E6%8A%A5&limit=30",
"看板": f"/workspaces/{ws_id}/items/board",
}
print("\n| 视图 | 首次 | P50 | P95 | 返回条数 |")
print("|---|---|---|---|---|")
for label, path in targets.items():
samples: list[float] = []
count = 0
for attempt in range(REPEAT):
t0 = time.perf_counter()
resp = await client.get(f"{BASE}{path}", headers=headers)
samples.append((time.perf_counter() - t0) * 1000)
if attempt == 0:
body = resp.json()["data"]
if "columns" in body:
count = sum(len(v) for v in body["columns"].values())
else:
count = len(body["items"])
samples.sort()
p50 = statistics.median(samples)
p95 = samples[min(len(samples) - 1, int(len(samples) * 0.95))]
print(f"| {label} | {samples[0]:.1f} ms | {p50:.1f} ms | {p95:.1f} ms | {count} |")
print(
"\n注:含网络往返与鉴权中间件;本机 127.0.0.1,所以这是**下限**,"
"真实用户还要加速度。"
)
if __name__ == "__main__":
asyncio.run(main())