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

1#!/usr/bin/env python3 

2""" 

3Web API for CPU benchmark data. 

4Endpoint: /server-list/api/cpu/benchmark 

5 

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""" 

10 

11import dataclasses 

12 

13import flask 

14 

15import server_list.spec.cpu_benchmark as cpu_benchmark 

16import server_list.spec.webapi as webapi 

17 

18cpu_api = flask.Blueprint("cpu_api", __name__) 

19 

20 

21@cpu_api.route("/cpu/benchmark", methods=["GET"]) 

22def get_cpu_benchmark(): 

23 """ 

24 Get CPU benchmark score. 

25 

26 Query parameters: 

27 cpu: CPU name to look up (required) 

28 fetch: If "true", queue background fetch if not in cache (optional) 

29 

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") 

35 

36 if not cpu_name: 

37 return webapi.error_response("CPU name is required", 400) 

38 

39 # Check database first 

40 result = cpu_benchmark.get_benchmark(cpu_name) 

41 

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) 

47 

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 }) 

59 

60 return webapi.error_response(f"Benchmark data not found for: {cpu_name}") 

61 

62 

63@cpu_api.route("/cpu/benchmark/batch", methods=["POST"]) 

64def get_cpu_benchmarks_batch(): 

65 """ 

66 Get CPU benchmark scores for multiple CPUs. 

67 

68 Request body (JSON): 

69 cpus: List of CPU names to look up 

70 fetch: If true, queue background fetch for missing CPUs (optional) 

71 

72 Returns: 

73 JSON with results for each CPU. 

74 Missing CPUs are marked with pending=true if background fetch was queued. 

75 

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() 

80 

81 if not data or "cpus" not in data: 

82 return webapi.error_response("CPU list is required", 400) 

83 

84 cpu_list = data["cpus"] 

85 should_fetch = data.get("fetch", False) 

86 results = {} 

87 missing_cpus = [] 

88 

89 # Batch fetch all benchmarks in a single query 

90 batch_results = cpu_benchmark.get_benchmarks_batch(cpu_list) 

91 

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 } 

109 

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 } 

121 

122 return flask.jsonify({ 

123 "success": True, 

124 "results": results 

125 })