Coverage for src / server_list / spec / webapi / cpu.py: 98%
48 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-31 11:45 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-31 11:45 +0000
1#!/usr/bin/env python3
2"""
3Web API for CPU benchmark data.
4Endpoint: /server-list/api/cpu/benchmark
6All endpoints respond immediately with cached data.
7If data is not cached and fetch is requested, a background task is queued
8and the frontend is notified via SSE when data becomes available.
9"""
11import dataclasses
13import flask
15import server_list.spec.cpu_benchmark as cpu_benchmark
16import server_list.spec.webapi as webapi
18cpu_api = flask.Blueprint("cpu_api", __name__)
21@cpu_api.route("/cpu/benchmark", methods=["GET"])
22def get_cpu_benchmark():
23 """
24 Get CPU benchmark score.
26 Query parameters:
27 cpu: CPU name to look up (required)
28 fetch: If "true", queue background fetch if not in cache (optional)
30 Returns:
31 JSON with cpu_name, multi_thread_score, single_thread_score
32 If data is not cached and fetch is requested, returns pending=true
33 """
34 cpu_name = flask.request.args.get("cpu")
36 if not cpu_name:
37 return webapi.error_response("CPU name is required", 400)
39 # Check database first
40 result = cpu_benchmark.get_benchmark(cpu_name)
42 if result:
43 result_dict = dataclasses.asdict(result)
44 result_dict["source"] = "cache"
45 result_dict["pending"] = False
46 return webapi.success_response(result_dict)
48 # Queue background fetch if requested
49 should_fetch = flask.request.args.get("fetch", "").lower() == "true"
50 if should_fetch:
51 queued = cpu_benchmark.queue_background_fetch(cpu_name)
52 pending = queued or cpu_benchmark.is_fetch_pending(cpu_name)
53 return flask.jsonify({
54 "success": True,
55 "data": None,
56 "pending": pending,
57 "message": "Fetching benchmark data in background" if pending else "Fetch already in progress",
58 })
60 return webapi.error_response(f"Benchmark data not found for: {cpu_name}")
63@cpu_api.route("/cpu/benchmark/batch", methods=["POST"])
64def get_cpu_benchmarks_batch():
65 """
66 Get CPU benchmark scores for multiple CPUs.
68 Request body (JSON):
69 cpus: List of CPU names to look up
70 fetch: If true, queue background fetch for missing CPUs (optional)
72 Returns:
73 JSON with results for each CPU.
74 Missing CPUs are marked with pending=true if background fetch was queued.
76 Optimized: Uses batch query to fetch all benchmarks in a single DB query.
77 Always responds immediately - no blocking on web requests.
78 """
79 data = flask.request.get_json()
81 if not data or "cpus" not in data:
82 return webapi.error_response("CPU list is required", 400)
84 cpu_list = data["cpus"]
85 should_fetch = data.get("fetch", False)
86 results = {}
87 missing_cpus = []
89 # Batch fetch all benchmarks in a single query
90 batch_results = cpu_benchmark.get_benchmarks_batch(cpu_list)
92 for cpu_name in cpu_list:
93 result = batch_results.get(cpu_name)
94 if result:
95 result_dict = dataclasses.asdict(result)
96 result_dict["source"] = "cache"
97 result_dict["pending"] = False
98 results[cpu_name] = {
99 "success": True,
100 "data": result_dict,
101 }
102 else:
103 missing_cpus.append(cpu_name)
104 results[cpu_name] = {
105 "success": False,
106 "data": None,
107 "pending": False,
108 }
110 # Queue background fetches for missing CPUs
111 if should_fetch and missing_cpus:
112 queued_count = cpu_benchmark.queue_background_fetch_batch(missing_cpus)
113 # Update pending status for missing CPUs
114 for cpu_name in missing_cpus:
115 results[cpu_name]["pending"] = cpu_benchmark.is_fetch_pending(cpu_name)
116 if queued_count > 0: 116 ↛ 122line 116 didn't jump to line 122 because the condition on line 116 was always true
117 results["_meta"] = {
118 "queued": queued_count,
119 "message": f"Queued {queued_count} background fetch(es)",
120 }
122 return flask.jsonify({
123 "success": True,
124 "results": results
125 })