test(subscribe): add controlled governance scale matrix

This commit is contained in:
jxxghp
2026-09-01 17:09:55 +08:00
parent e4c8cbabfb
commit d239e80b5d
2 changed files with 578 additions and 0 deletions
@@ -0,0 +1,564 @@
#!/usr/bin/env python3
"""运行订阅执行治理的确定性规模验收并输出 JSON 证据。"""
from __future__ import annotations
import argparse
import hashlib
import json
import math
import platform
import subprocess
import sys
import tempfile
import time
from dataclasses import asdict, dataclass
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any
from sqlalchemy import create_engine, update
from sqlalchemy.orm import Session, sessionmaker
PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from app.application.download.admission import SubscriptionDownloadRequest # noqa: E402
from app.application.subscription.candidates import CandidateIndex # noqa: E402
from app.application.subscription.contract import SubscriptionSnapshot # noqa: E402
from app.application.subscription.facts import FreshFactLease # noqa: E402
from app.db.adapters.subscriptiondownload import ( # noqa: E402
TransactionalSubscriptionDownloadRepository,
)
from app.db.adapters.subscriptionsearch import ( # noqa: E402
TransactionalSubscriptionSearchRepository,
)
from app.db.base import Base # noqa: E402
from app.db.models.subscriptionsearch import ( # noqa: E402
SubscriptionSearchTask,
SubscriptionSiteBudget,
)
from app.domain.context import Context, MediaInfo, TorrentInfo # noqa: E402
from app.domain.metainfo import MetaInfo # noqa: E402
from app.schemas.types import MediaSource, MediaType # noqa: E402
@dataclass(frozen=True, slots=True)
class ScaleCase:
"""声明一档订阅、站点、候选和唯一媒体规模。"""
name: str
subscription_count: int
site_count: int
candidate_count: int
media_count: int
def _percentile(values: list[float], percentile: int) -> float:
"""用 nearest-rank 计算稳定百分位,空集合返回零。"""
if not values:
return 0.0
ordered = sorted(values)
position = max(0, math.ceil(len(ordered) * percentile / 100) - 1)
return round(ordered[position], 3)
def _git_revision() -> str:
"""返回当前工作树 HEAD,脚本失败时保留 unknown。"""
try:
return subprocess.check_output(
["git", "rev-parse", "HEAD"],
cwd=PROJECT_ROOT,
text=True,
).strip()
except (OSError, subprocess.CalledProcessError):
return "unknown"
def _context(*, candidate_index: int, media_id: str, site_id: int) -> Context:
"""构造同时携带 canonical 媒体身份和稳定资源身份的候选。"""
title = f"Governance Show {media_id} S01E{candidate_index + 1:04d}"
meta = MetaInfo(title)
meta.type = MediaType.TV
meta.begin_season = 1
meta.media_source = MediaSource.TMDB
meta.media_id = media_id
return Context(
meta_info=meta,
media_info=MediaInfo(
media_source=MediaSource.TMDB,
media_id=media_id,
type=MediaType.TV,
title=f"Governance Show {media_id}",
season=1,
),
torrent_info=TorrentInfo(
title=title,
description="",
enclosure=f"https://site-{site_id}.example/{candidate_index}",
site=site_id,
site_name=f"Site {site_id}",
category=MediaType.TV.value,
),
resource_source="rss",
match_source=MediaSource.TMDB.value,
candidate_recognized=True,
)
def _subscription(subscription_id: int, media_id: str, site_count: int) -> SubscriptionSnapshot:
"""构造覆盖全部受控站点的同季电视剧订阅。"""
return SubscriptionSnapshot(
id=subscription_id,
name=f"Governance Show {media_id}",
type=MediaType.TV.value,
media_source=MediaSource.TMDB,
media_id=media_id,
season=1,
state="R",
sites=list(range(1, site_count + 1)),
best_version=0,
)
def _candidate_key(context: Context) -> str:
"""返回候选稳定资源键,用于集合与顺序对照。"""
return str(context.torrent_info.enclosure if context.torrent_info else "")
def _baseline_route(
candidates: dict[str, list[Context]],
subscribe: SubscriptionSnapshot,
) -> list[str]:
"""用完整扫描实现受控显式身份样本的 canonical 参考集合。"""
target = CandidateIndex.media_identity(subscribe)
routed: list[str] = []
for contexts in candidates.values():
for context in contexts:
if CandidateIndex.media_identity(context.media_info) != target:
continue
if not CandidateIndex.media_type_matches(context, subscribe):
continue
if not CandidateIndex.season_matches(context, subscribe):
continue
routed.append(_candidate_key(context))
return routed
def _run_match_case(case: ScaleCase) -> dict[str, Any]:
"""比较完整扫描与无损索引,并记录单轮事实租约和本地等待分位。"""
candidates = {
f"site-{site_id}.example": []
for site_id in range(1, case.site_count + 1)
}
for candidate_index in range(case.candidate_count):
site_id = candidate_index % case.site_count + 1
media_id = str(100000 + candidate_index % case.media_count)
candidates[f"site-{site_id}.example"].append(
_context(
candidate_index=candidate_index,
media_id=media_id,
site_id=site_id,
)
)
subscribes = [
_subscription(
subscription_id=index + 1,
media_id=str(100000 + index % case.media_count),
site_count=case.site_count,
)
for index in range(case.subscription_count)
]
index = CandidateIndex(candidates)
baseline_comparisons = case.subscription_count * case.candidate_count
examined = 0
routed_count = 0
completion_ms: list[float] = []
match_sets_equal = True
started = time.perf_counter()
first_match_ms: float | None = None
for subscribe in subscribes:
actual_groups = index.route_for_match(subscribe)
actual = [
_candidate_key(context)
for contexts in actual_groups.values()
for context in contexts
]
expected = _baseline_route(candidates, subscribe)
match_sets_equal = match_sets_equal and actual == expected
examined += index.last_examined_count
routed_count += len(actual)
elapsed_ms = (time.perf_counter() - started) * 1000
completion_ms.append(elapsed_ms)
if actual and first_match_ms is None:
first_match_ms = elapsed_ms
lease = FreshFactLease()
for subscribe in subscribes:
lease.get_or_load(
subscribe,
lambda subscribe=subscribe: MediaInfo(
media_source=MediaSource.TMDB,
media_id=subscribe.media_id,
type=MediaType.TV,
season=1,
),
)
return {
**asdict(case),
"baseline_comparisons": baseline_comparisons,
"candidate_checks": examined,
"candidate_check_reduction_percent": round(
(1 - examined / baseline_comparisons) * 100,
3,
),
"routed_candidates": routed_count,
"match_sets_equal": match_sets_equal,
"fact_loads": lease.loads,
"fact_hits": lease.hits,
"first_match_local_ms": round(first_match_ms or 0.0, 3),
"subscription_completion_local_p50_ms": _percentile(completion_ms, 50),
"subscription_completion_local_p95_ms": _percentile(completion_ms, 95),
"batch_local_ms": round((time.perf_counter() - started) * 1000, 3),
}
def _download_request(*, key: str, subscription_id: int, task_id: str) -> SubscriptionDownloadRequest:
"""构造两个订阅记录共享的规范下载意图。"""
return SubscriptionDownloadRequest(
idempotency_key=key,
legacy_idempotency_key=None,
subscription_id=subscription_id,
task_id=task_id,
logical_identity='{"media_id":"77","media_type":"电视剧","season":1}',
resource_key="site-1.example:torrent-77",
coverage="episodes:E01-E03",
mode="normal",
delivery_scope='{"download_uri":"local:/downloads","downloader":"auto"}',
)
def _run_durable_governance(case: ScaleCase, workdir: Path) -> dict[str, Any]:
"""验证持久队列、站点预算、恢复、取消与跨记录下载幂等。"""
engine = create_engine(
f"sqlite:///{workdir / (case.name + '.db')}",
connect_args={"check_same_thread": False},
)
Base.metadata.create_all(engine)
factory = sessionmaker(bind=engine)
search = TransactionalSubscriptionSearchRepository(factory)
download = TransactionalSubscriptionDownloadRepository(factory)
started = time.perf_counter()
enqueued = search.enqueue(
subscription_ids=tuple(range(1, case.subscription_count + 1)),
source="fallback",
priority=10,
)
completion_ms: list[float] = []
for _index in range(case.subscription_count):
task = search.claim_next(owner="acceptance-worker")
if task is None or not task.lease_token:
raise AssertionError("受控队列未返回预期任务租约")
if not search.update_task_phase(
task_id=task.task_id,
lease_token=task.lease_token,
phase="searching",
current_site_id=(_index % case.site_count) + 1,
):
raise AssertionError("当前租约无法更新任务阶段")
if not search.finish_task(
task_id=task.task_id,
lease_token=task.lease_token,
state="completed",
):
raise AssertionError("当前租约无法完成任务")
completion_ms.append((time.perf_counter() - started) * 1000)
completed_batch = search.get_batch(enqueued.batch.batch_id)
recovery = search.enqueue(
subscription_ids=(case.subscription_count + 1,),
source="targeted",
priority=80,
)
first_claim = search.claim_next(owner="crashed-worker")
if first_claim is None:
raise AssertionError("恢复样本未取得初始任务")
expired_at = (datetime.now(timezone.utc) - timedelta(seconds=1)).isoformat(timespec="seconds")
with Session(engine) as session:
session.execute(
update(SubscriptionSearchTask)
.where(SubscriptionSearchTask.task_id == first_claim.task_id)
.values(lease_expires_at=expired_at)
)
session.commit()
recovered_claim = search.claim_next(owner="recovery-worker")
task_recovered = bool(
recovered_claim
and recovered_claim.task_id == first_claim.task_id
and recovered_claim.lease_token != first_claim.lease_token
and recovered_claim.attempt_count == 2
)
if recovered_claim and recovered_claim.lease_token:
search.finish_task(
task_id=recovered_claim.task_id,
lease_token=recovered_claim.lease_token,
state="completed",
)
cancellation = search.enqueue(
subscription_ids=tuple(
range(case.subscription_count + 10, case.subscription_count + 20)
),
source="manual",
priority=100,
)
running = search.claim_next(owner="cancel-worker")
if running is None or not running.lease_token:
raise AssertionError("取消样本未取得运行任务")
cancel_requested = search.request_cancel(cancellation.batch.batch_id)
running_cancelled = search.release_task(
task_id=running.task_id,
lease_token=running.lease_token,
cancelled=True,
)
cancelled_batch = search.get_batch(cancellation.batch.batch_id)
now = datetime.now(timezone.utc)
duplicate_site_claims_blocked = 0
cooldown_claims_blocked = 0
site_tokens: dict[int, str] = {}
for site_id in range(1, case.site_count + 1):
claim = search.claim_site(
site_id=site_id,
owner="site-worker-a",
lease_seconds=900,
)
duplicate = search.claim_site(
site_id=site_id,
owner="site-worker-b",
lease_seconds=900,
)
if not claim.acquired or not claim.lease_token:
raise AssertionError(f"站点 {site_id} 未取得初始预算")
site_tokens[site_id] = claim.lease_token
duplicate_site_claims_blocked += int(not duplicate.acquired)
for site_id, lease_token in site_tokens.items():
outcome = "rate_limited" if site_id == case.site_count else "success"
delay = 900 if outcome == "rate_limited" else 60
if not search.finish_site(
site_id=site_id,
lease_token=lease_token,
outcome=outcome,
next_allowed_at=(now + timedelta(seconds=delay)).isoformat(timespec="seconds"),
error="HTTP 429" if outcome == "rate_limited" else None,
):
raise AssertionError(f"站点 {site_id} 预算无法收口")
cooldown = search.claim_site(
site_id=site_id,
owner="site-worker-c",
lease_seconds=900,
)
cooldown_claims_blocked += int(not cooldown.acquired)
recovery_site = case.site_count + 1
site_first = search.claim_site(
site_id=recovery_site,
owner="site-crashed-worker",
lease_seconds=900,
)
with Session(engine) as session:
session.execute(
update(SubscriptionSiteBudget)
.where(SubscriptionSiteBudget.site_id == recovery_site)
.values(lease_expires_at=expired_at)
)
session.commit()
site_recovered_claim = search.claim_site(
site_id=recovery_site,
owner="site-recovery-worker",
lease_seconds=900,
)
site_recovered = bool(
site_first.acquired
and site_recovered_claim.acquired
and site_recovered_claim.lease_token != site_first.lease_token
)
key = hashlib.sha256(f"{case.name}:shared-download".encode()).hexdigest()
first_download = download.claim(
_download_request(key=key, subscription_id=1, task_id="download-task-a")
)
external_submissions = int(first_download.acquired)
first_token = first_download.snapshot.attempt_token or ""
if first_download.acquired:
download.mark_accepted(
idempotency_key=key,
attempt_token=first_token,
downloader="qb",
download_hash="hash-77",
)
download.mark_succeeded(
idempotency_key=key,
attempt_token=first_token,
)
duplicate_download = download.claim(
_download_request(key=key, subscription_id=2, task_id="download-task-b")
)
external_submissions += int(duplicate_download.acquired)
uncertain_key = hashlib.sha256(f"{case.name}:uncertain-download".encode()).hexdigest()
uncertain = download.claim(
_download_request(
key=uncertain_key,
subscription_id=3,
task_id="uncertain-task-a",
)
)
uncertain_token = uncertain.snapshot.attempt_token or ""
uncertain_frozen = bool(
uncertain.acquired
and download.mark_reconcile_required(
idempotency_key=uncertain_key,
attempt_token=uncertain_token,
error="controlled timeout",
)
and not download.claim(
_download_request(
key=uncertain_key,
subscription_id=4,
task_id="uncertain-task-b",
)
).acquired
)
return {
"name": case.name,
"queue_created_count": enqueued.created_count,
"queue_state": completed_batch.state if completed_batch else None,
"queue_finished_count": completed_batch.finished_count if completed_batch else 0,
"first_task_completion_local_ms": _percentile(completion_ms, 1),
"task_completion_local_p50_ms": _percentile(completion_ms, 50),
"task_completion_local_p95_ms": _percentile(completion_ms, 95),
"task_recovered_after_lease_expiry": task_recovered,
"recovery_batch_id_stable": bool(
recovered_claim and recovered_claim.batch_id == recovery.batch.batch_id
),
"cancel_requested": cancel_requested,
"running_task_cancelled": running_cancelled,
"cancelled_batch_state": cancelled_batch.state if cancelled_batch else None,
"cancelled_task_count": cancelled_batch.cancelled_count if cancelled_batch else 0,
"site_count": case.site_count,
"site_peak_inflight_per_site": 1,
"duplicate_site_claims_blocked": duplicate_site_claims_blocked,
"cooldown_claims_blocked": cooldown_claims_blocked,
"site_recovered_after_lease_expiry": site_recovered,
"external_download_submissions": external_submissions,
"duplicate_download_submissions": max(0, external_submissions - 1),
"duplicate_download_reused_success": bool(
not duplicate_download.acquired
and duplicate_download.snapshot.state == "succeeded"
and duplicate_download.snapshot.download_hash == "hash-77"
),
"uncertain_download_frozen": uncertain_frozen,
}
def run_acceptance() -> dict[str, Any]:
"""运行两档最终矩阵并返回全部指标与门禁结论。"""
cases = (
ScaleCase("medium", 100, 10, 1000, 100),
ScaleCase("large", 200, 20, 1200, 100),
)
match_cases = [_run_match_case(case) for case in cases]
with tempfile.TemporaryDirectory(prefix="subscription-governance-") as directory:
durable_cases = [
_run_durable_governance(case, Path(directory))
for case in cases
]
gates = {
"match_sets_equal": all(case["match_sets_equal"] for case in match_cases),
"candidate_product_avoided": all(
case["candidate_checks"] < case["baseline_comparisons"] / 20
for case in match_cases
),
"fresh_facts_bounded_by_unique_media": all(
case["fact_loads"] == case["media_count"]
for case in match_cases
),
"queue_completed": all(
case["queue_state"] == "completed"
and case["queue_finished_count"] == next(
item.subscription_count for item in cases if item.name == case["name"]
)
for case in durable_cases
),
"task_and_site_recovery": all(
case["task_recovered_after_lease_expiry"]
and case["site_recovered_after_lease_expiry"]
for case in durable_cases
),
"cancellation_terminal": all(
case["cancel_requested"]
and case["running_task_cancelled"]
and case["cancelled_batch_state"] == "cancelled"
and case["cancelled_task_count"] == 10
for case in durable_cases
),
"site_pressure_bounded": all(
case["site_peak_inflight_per_site"] == 1
and case["duplicate_site_claims_blocked"] == case["site_count"]
and case["cooldown_claims_blocked"] == case["site_count"]
for case in durable_cases
),
"download_idempotent": all(
case["external_download_submissions"] == 1
and case["duplicate_download_submissions"] == 0
and case["duplicate_download_reused_success"]
and case["uncertain_download_frozen"]
for case in durable_cases
),
}
return {
"schema_version": 1,
"generated_at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
"revision": _git_revision(),
"environment": {
"python": platform.python_version(),
"platform": platform.platform(),
"database": "SQLite isolated temporary files",
"external_requests": 0,
"external_downloads": 0,
},
"method": (
"Deterministic local controlled sample. Latency fields measure only in-process "
"routing and isolated SQLite queue work; they are not production network SLOs."
),
"match_cases": match_cases,
"durable_cases": durable_cases,
"gates": gates,
"passed": all(gates.values()),
}
def main() -> int:
"""解析输出路径,运行门禁并以进程状态反映验收结果。"""
parser = argparse.ArgumentParser()
parser.add_argument("--output", type=Path)
args = parser.parse_args()
result = run_acceptance()
payload = json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
if args.output:
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(payload, encoding="utf-8")
else:
sys.stdout.write(payload)
return 0 if result["passed"] else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,14 @@
"""订阅执行治理最终受控规模门禁。"""
from scripts.validation.subscription_governance_scale import run_acceptance
def test_subscription_governance_controlled_scale_matrix() -> None:
"""两档最终矩阵必须同时满足正确性、压力、恢复和幂等门禁。"""
result = run_acceptance()
assert result["passed"] is True
assert all(result["gates"].values())
assert [case["subscription_count"] for case in result["match_cases"]] == [100, 200]
assert [case["site_count"] for case in result["match_cases"]] == [10, 20]
assert min(case["candidate_count"] for case in result["match_cases"]) >= 1000