jettask 0.2.14__py3-none-any.whl → 0.2.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. jettask/__init__.py +14 -35
  2. jettask/{webui/__main__.py → __main__.py} +4 -4
  3. jettask/api/__init__.py +103 -0
  4. jettask/api/v1/__init__.py +29 -0
  5. jettask/api/v1/alerts.py +226 -0
  6. jettask/api/v1/analytics.py +323 -0
  7. jettask/api/v1/namespaces.py +134 -0
  8. jettask/api/v1/overview.py +136 -0
  9. jettask/api/v1/queues.py +530 -0
  10. jettask/api/v1/scheduled.py +420 -0
  11. jettask/api/v1/settings.py +44 -0
  12. jettask/{webui/api.py → api.py} +4 -46
  13. jettask/{webui/backend → backend}/main.py +21 -109
  14. jettask/{webui/backend → backend}/main_unified.py +1 -1
  15. jettask/{webui/backend → backend}/namespace_api_old.py +3 -30
  16. jettask/{webui/backend → backend}/namespace_data_access.py +2 -1
  17. jettask/{webui/backend → backend}/unified_api_router.py +14 -74
  18. jettask/{core/cli.py → cli.py} +106 -26
  19. jettask/config/nacos_config.py +386 -0
  20. jettask/core/app.py +8 -100
  21. jettask/core/db_manager.py +515 -0
  22. jettask/core/event_pool.py +5 -2
  23. jettask/core/unified_manager_base.py +47 -14
  24. jettask/{webui/db_init.py → db_init.py} +1 -1
  25. jettask/executors/asyncio.py +2 -2
  26. jettask/{webui/integrated_gradio_app.py → integrated_gradio_app.py} +1 -1
  27. jettask/{webui/multi_namespace_consumer.py → multi_namespace_consumer.py} +5 -2
  28. jettask/{webui/pg_consumer.py → pg_consumer.py} +137 -69
  29. jettask/{webui/run.py → run.py} +1 -1
  30. jettask/{webui/run_webui.py → run_webui.py} +4 -4
  31. jettask/scheduler/multi_namespace_scheduler.py +2 -2
  32. jettask/scheduler/unified_manager.py +5 -5
  33. jettask/scheduler/unified_scheduler_manager.py +1 -1
  34. jettask/schemas/__init__.py +166 -0
  35. jettask/schemas/alert.py +99 -0
  36. jettask/schemas/backlog.py +122 -0
  37. jettask/schemas/common.py +139 -0
  38. jettask/schemas/monitoring.py +181 -0
  39. jettask/schemas/namespace.py +168 -0
  40. jettask/schemas/queue.py +83 -0
  41. jettask/schemas/scheduled_task.py +128 -0
  42. jettask/schemas/task.py +70 -0
  43. jettask/services/__init__.py +24 -0
  44. jettask/services/alert_service.py +454 -0
  45. jettask/services/analytics_service.py +46 -0
  46. jettask/services/overview_service.py +978 -0
  47. jettask/services/queue_service.py +711 -0
  48. jettask/services/redis_monitor_service.py +151 -0
  49. jettask/services/scheduled_task_service.py +207 -0
  50. jettask/services/settings_service.py +758 -0
  51. jettask/services/task_service.py +157 -0
  52. jettask/{webui/task_center.py → task_center.py} +30 -8
  53. jettask/{webui/task_center_client.py → task_center_client.py} +1 -1
  54. jettask/{webui/config.py → webui_config.py} +6 -1
  55. jettask/webui_exceptions.py +67 -0
  56. jettask/webui_sql/verify_database.sql +72 -0
  57. {jettask-0.2.14.dist-info → jettask-0.2.16.dist-info}/METADATA +3 -1
  58. jettask-0.2.16.dist-info/RECORD +150 -0
  59. {jettask-0.2.14.dist-info → jettask-0.2.16.dist-info}/entry_points.txt +1 -1
  60. jettask/webui/backend/data_api.py +0 -3294
  61. jettask/webui/backend/namespace_api.py +0 -295
  62. jettask/webui/backend/queue_backlog_api.py +0 -727
  63. jettask/webui/backend/redis_monitor_api.py +0 -476
  64. jettask/webui/frontend/index.html +0 -13
  65. jettask/webui/frontend/package.json +0 -30
  66. jettask/webui/frontend/src/App.css +0 -109
  67. jettask/webui/frontend/src/App.jsx +0 -66
  68. jettask/webui/frontend/src/components/NamespaceSelector.jsx +0 -166
  69. jettask/webui/frontend/src/components/QueueBacklogChart.jsx +0 -298
  70. jettask/webui/frontend/src/components/QueueBacklogTrend.jsx +0 -638
  71. jettask/webui/frontend/src/components/QueueDetailsTable.css +0 -65
  72. jettask/webui/frontend/src/components/QueueDetailsTable.jsx +0 -487
  73. jettask/webui/frontend/src/components/QueueDetailsTableV2.jsx +0 -465
  74. jettask/webui/frontend/src/components/ScheduledTaskFilter.jsx +0 -423
  75. jettask/webui/frontend/src/components/TaskFilter.jsx +0 -425
  76. jettask/webui/frontend/src/components/TimeRangeSelector.css +0 -21
  77. jettask/webui/frontend/src/components/TimeRangeSelector.jsx +0 -160
  78. jettask/webui/frontend/src/components/charts/QueueChart.jsx +0 -111
  79. jettask/webui/frontend/src/components/charts/QueueTrendChart.jsx +0 -115
  80. jettask/webui/frontend/src/components/charts/WorkerChart.jsx +0 -40
  81. jettask/webui/frontend/src/components/common/StatsCard.jsx +0 -18
  82. jettask/webui/frontend/src/components/layout/AppLayout.css +0 -95
  83. jettask/webui/frontend/src/components/layout/AppLayout.jsx +0 -49
  84. jettask/webui/frontend/src/components/layout/Header.css +0 -106
  85. jettask/webui/frontend/src/components/layout/Header.jsx +0 -106
  86. jettask/webui/frontend/src/components/layout/SideMenu.css +0 -137
  87. jettask/webui/frontend/src/components/layout/SideMenu.jsx +0 -209
  88. jettask/webui/frontend/src/components/layout/TabsNav.css +0 -244
  89. jettask/webui/frontend/src/components/layout/TabsNav.jsx +0 -206
  90. jettask/webui/frontend/src/components/layout/UserInfo.css +0 -197
  91. jettask/webui/frontend/src/components/layout/UserInfo.jsx +0 -197
  92. jettask/webui/frontend/src/contexts/LoadingContext.jsx +0 -27
  93. jettask/webui/frontend/src/contexts/NamespaceContext.jsx +0 -72
  94. jettask/webui/frontend/src/contexts/TabsContext.backup.jsx +0 -245
  95. jettask/webui/frontend/src/index.css +0 -114
  96. jettask/webui/frontend/src/main.jsx +0 -22
  97. jettask/webui/frontend/src/pages/Alerts.jsx +0 -684
  98. jettask/webui/frontend/src/pages/Dashboard/index.css +0 -35
  99. jettask/webui/frontend/src/pages/Dashboard/index.jsx +0 -281
  100. jettask/webui/frontend/src/pages/Dashboard.jsx +0 -1330
  101. jettask/webui/frontend/src/pages/QueueDetail.jsx +0 -1117
  102. jettask/webui/frontend/src/pages/QueueMonitor.jsx +0 -527
  103. jettask/webui/frontend/src/pages/Queues.jsx +0 -12
  104. jettask/webui/frontend/src/pages/ScheduledTasks.jsx +0 -810
  105. jettask/webui/frontend/src/pages/Settings.jsx +0 -801
  106. jettask/webui/frontend/src/pages/Workers.jsx +0 -12
  107. jettask/webui/frontend/src/services/api.js +0 -159
  108. jettask/webui/frontend/src/services/queueTrend.js +0 -166
  109. jettask/webui/frontend/src/utils/suppressWarnings.js +0 -22
  110. jettask/webui/frontend/src/utils/userPreferences.js +0 -154
  111. jettask/webui/frontend/vite.config.js +0 -26
  112. jettask/webui/sql/init_database.sql +0 -640
  113. jettask-0.2.14.dist-info/RECORD +0 -172
  114. /jettask/{webui/backend → backend}/__init__.py +0 -0
  115. /jettask/{webui/backend → backend}/api/__init__.py +0 -0
  116. /jettask/{webui/backend → backend}/api/v1/__init__.py +0 -0
  117. /jettask/{webui/backend → backend}/api/v1/monitoring.py +0 -0
  118. /jettask/{webui/backend → backend}/api/v1/namespaces.py +0 -0
  119. /jettask/{webui/backend → backend}/api/v1/queues.py +0 -0
  120. /jettask/{webui/backend → backend}/api/v1/tasks.py +0 -0
  121. /jettask/{webui/backend → backend}/config.py +0 -0
  122. /jettask/{webui/backend → backend}/core/__init__.py +0 -0
  123. /jettask/{webui/backend → backend}/core/cache.py +0 -0
  124. /jettask/{webui/backend → backend}/core/database.py +0 -0
  125. /jettask/{webui/backend → backend}/core/exceptions.py +0 -0
  126. /jettask/{webui/backend → backend}/data_access.py +0 -0
  127. /jettask/{webui/backend → backend}/dependencies.py +0 -0
  128. /jettask/{webui/backend → backend}/init_meta_db.py +0 -0
  129. /jettask/{webui/backend → backend}/main_v2.py +0 -0
  130. /jettask/{webui/backend → backend}/models/__init__.py +0 -0
  131. /jettask/{webui/backend → backend}/models/requests.py +0 -0
  132. /jettask/{webui/backend → backend}/models/responses.py +0 -0
  133. /jettask/{webui/backend → backend}/queue_stats_v2.py +0 -0
  134. /jettask/{webui/backend → backend}/services/__init__.py +0 -0
  135. /jettask/{webui/backend → backend}/start.py +0 -0
  136. /jettask/{webui/cleanup_deprecated_tables.sql → cleanup_deprecated_tables.sql} +0 -0
  137. /jettask/{webui/gradio_app.py → gradio_app.py} +0 -0
  138. /jettask/{webui/__init__.py → main.py} +0 -0
  139. /jettask/{webui/models.py → models.py} +0 -0
  140. /jettask/{webui/run_monitor.py → run_monitor.py} +0 -0
  141. /jettask/{webui/schema.sql → schema.sql} +0 -0
  142. /jettask/{webui/unified_consumer_manager.py → unified_consumer_manager.py} +0 -0
  143. /jettask/{webui/models → webui_models}/__init__.py +0 -0
  144. /jettask/{webui/models → webui_models}/namespace.py +0 -0
  145. /jettask/{webui/sql → webui_sql}/batch_upsert_functions.sql +0 -0
  146. {jettask-0.2.14.dist-info → jettask-0.2.16.dist-info}/WHEEL +0 -0
  147. {jettask-0.2.14.dist-info → jettask-0.2.16.dist-info}/licenses/LICENSE +0 -0
  148. {jettask-0.2.14.dist-info → jettask-0.2.16.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,323 @@
1
+ """
2
+ 分析模块 - 数据分析、查询和报表
3
+ 提供轻量级的路由入口,业务逻辑在 AnalyticsService 中实现
4
+ """
5
+ from fastapi import APIRouter, HTTPException, Request, Query
6
+ from typing import List, Dict, Optional, Any
7
+ from datetime import datetime
8
+ import logging
9
+
10
+ from jettask.schemas import TimeRangeQuery
11
+ from jettask.services.analytics_service import AnalyticsService
12
+ from jettask.backend.namespace_data_access import get_namespace_data_access
13
+
14
+ router = APIRouter(prefix="/analytics", tags=["analytics"])
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # 获取全局数据访问实例
18
+ data_access = get_namespace_data_access()
19
+
20
+
21
+ # ============ 命名空间管理 ============
22
+
23
+ @router.get("/namespaces")
24
+ async def get_all_namespaces():
25
+ """
26
+ 获取所有配置的命名空间列表
27
+ """
28
+ try:
29
+ namespaces = await data_access.get_all_namespaces()
30
+ return {
31
+ "success": True,
32
+ "data": namespaces
33
+ }
34
+ except Exception as e:
35
+ logger.error(f"获取命名空间列表失败: {e}")
36
+ raise HTTPException(status_code=500, detail=str(e))
37
+
38
+
39
+ # ============ 队列统计 ============
40
+
41
+ @router.get("/queue-stats/{namespace}")
42
+ async def get_queue_stats(namespace: str):
43
+ """
44
+ 获取指定命名空间的队列统计信息
45
+
46
+ Args:
47
+ namespace: 命名空间名称
48
+ """
49
+ try:
50
+ stats = await data_access.get_queue_stats(namespace)
51
+ return {
52
+ "success": True,
53
+ "data": stats
54
+ }
55
+ except Exception as e:
56
+ logger.error(f"获取队列统计失败: {e}")
57
+ raise HTTPException(status_code=500, detail=str(e))
58
+
59
+
60
+ @router.post("/queue-trends/{namespace}")
61
+ async def get_queue_trends(namespace: str, request: Request):
62
+ """
63
+ 获取队列趋势数据
64
+
65
+ Args:
66
+ namespace: 命名空间名称
67
+ """
68
+ try:
69
+ # 解析请求体
70
+ body = await request.json() if await request.body() else {}
71
+
72
+ # 从请求体中获取参数
73
+ time_range = body.get('time_range', '1h')
74
+ queue_name = body.get('queue_name')
75
+ granularity = body.get('granularity', 'minute')
76
+
77
+ # TODO: 实现队列趋势分析
78
+ return {
79
+ "success": True,
80
+ "namespace": namespace,
81
+ "time_range": time_range,
82
+ "queue_name": queue_name,
83
+ "data": [],
84
+ "granularity": granularity
85
+ }
86
+ except Exception as e:
87
+ logger.error(f"获取队列趋势失败: {e}")
88
+ raise HTTPException(status_code=500, detail=str(e))
89
+
90
+
91
+ # ============ 任务分析 ============
92
+
93
+ @router.post("/task-analysis/{namespace}")
94
+ async def analyze_tasks(namespace: str, request: Request):
95
+ """
96
+ 分析任务执行情况
97
+
98
+ Args:
99
+ namespace: 命名空间名称
100
+ """
101
+ try:
102
+ body = await request.json()
103
+
104
+ # TODO: 实现任务分析逻辑
105
+ return {
106
+ "success": True,
107
+ "data": {
108
+ "total_tasks": 0,
109
+ "success_rate": 0.0,
110
+ "avg_execution_time": 0.0,
111
+ "error_distribution": {}
112
+ }
113
+ }
114
+ except Exception as e:
115
+ logger.error(f"任务分析失败: {e}")
116
+ raise HTTPException(status_code=500, detail=str(e))
117
+
118
+
119
+ @router.get("/task-distribution/{namespace}")
120
+ async def get_task_distribution(
121
+ namespace: str,
122
+ time_range: str = Query("24h", description="时间范围")
123
+ ):
124
+ """
125
+ 获取任务分布情况
126
+
127
+ Args:
128
+ namespace: 命名空间名称
129
+ time_range: 时间范围
130
+ """
131
+ try:
132
+ # TODO: 实现任务分布统计
133
+ return {
134
+ "success": True,
135
+ "data": {
136
+ "by_queue": {},
137
+ "by_status": {},
138
+ "by_worker": {},
139
+ "by_hour": []
140
+ }
141
+ }
142
+ except Exception as e:
143
+ logger.error(f"获取任务分布失败: {e}")
144
+ raise HTTPException(status_code=500, detail=str(e))
145
+
146
+
147
+ # ============ 性能分析 ============
148
+
149
+ @router.get("/performance-metrics/{namespace}")
150
+ async def get_performance_metrics(
151
+ namespace: str,
152
+ time_range: str = Query("1h", description="时间范围")
153
+ ):
154
+ """
155
+ 获取性能指标
156
+
157
+ Args:
158
+ namespace: 命名空间名称
159
+ time_range: 时间范围
160
+ """
161
+ try:
162
+ # TODO: 实现性能指标收集
163
+ return {
164
+ "success": True,
165
+ "data": {
166
+ "throughput": 0,
167
+ "latency": {
168
+ "p50": 0,
169
+ "p95": 0,
170
+ "p99": 0
171
+ },
172
+ "error_rate": 0,
173
+ "queue_depth": 0
174
+ }
175
+ }
176
+ except Exception as e:
177
+ logger.error(f"获取性能指标失败: {e}")
178
+ raise HTTPException(status_code=500, detail=str(e))
179
+
180
+
181
+ @router.get("/bottlenecks/{namespace}")
182
+ async def identify_bottlenecks(namespace: str):
183
+ """
184
+ 识别系统瓶颈
185
+
186
+ Args:
187
+ namespace: 命名空间名称
188
+ """
189
+ try:
190
+ # TODO: 实现瓶颈分析
191
+ return {
192
+ "success": True,
193
+ "data": {
194
+ "slow_queues": [],
195
+ "high_error_queues": [],
196
+ "high_latency_tasks": [],
197
+ "recommendations": []
198
+ }
199
+ }
200
+ except Exception as e:
201
+ logger.error(f"识别瓶颈失败: {e}")
202
+ raise HTTPException(status_code=500, detail=str(e))
203
+
204
+
205
+ # ============ 报表生成 ============
206
+
207
+ @router.post("/reports/generate/{namespace}")
208
+ async def generate_report(
209
+ namespace: str,
210
+ request: Request
211
+ ):
212
+ """
213
+ 生成分析报表
214
+
215
+ Args:
216
+ namespace: 命名空间名称
217
+ """
218
+ try:
219
+ body = await request.json()
220
+ report_type = body.get("report_type", "daily")
221
+ start_time = body.get("start_time")
222
+ end_time = body.get("end_time")
223
+
224
+ # TODO: 实现报表生成
225
+ return {
226
+ "success": True,
227
+ "data": {
228
+ "report_id": f"report_{namespace}_{datetime.now().strftime('%Y%m%d%H%M%S')}",
229
+ "report_type": report_type,
230
+ "status": "generated",
231
+ "url": None
232
+ }
233
+ }
234
+ except Exception as e:
235
+ logger.error(f"生成报表失败: {e}")
236
+ raise HTTPException(status_code=500, detail=str(e))
237
+
238
+
239
+ @router.get("/reports/{report_id}")
240
+ async def get_report(report_id: str):
241
+ """
242
+ 获取报表内容
243
+
244
+ Args:
245
+ report_id: 报表ID
246
+ """
247
+ try:
248
+ # TODO: 实现报表获取
249
+ return {
250
+ "success": True,
251
+ "data": {
252
+ "report_id": report_id,
253
+ "content": {},
254
+ "generated_at": datetime.now().isoformat()
255
+ }
256
+ }
257
+ except Exception as e:
258
+ logger.error(f"获取报表失败: {e}")
259
+ raise HTTPException(status_code=500, detail=str(e))
260
+
261
+
262
+ # ============ 实时监控 ============
263
+
264
+ @router.get("/realtime/{namespace}/stats")
265
+ async def get_realtime_stats(namespace: str):
266
+ """
267
+ 获取实时统计数据
268
+
269
+ Args:
270
+ namespace: 命名空间名称
271
+ """
272
+ try:
273
+ # TODO: 实现实时统计
274
+ return {
275
+ "success": True,
276
+ "data": {
277
+ "timestamp": datetime.now().isoformat(),
278
+ "active_tasks": 0,
279
+ "queued_tasks": 0,
280
+ "completed_last_minute": 0,
281
+ "failed_last_minute": 0,
282
+ "avg_processing_time": 0.0
283
+ }
284
+ }
285
+ except Exception as e:
286
+ logger.error(f"获取实时统计失败: {e}")
287
+ raise HTTPException(status_code=500, detail=str(e))
288
+
289
+
290
+ # ============ 数据导出 ============
291
+
292
+ @router.post("/export/{namespace}")
293
+ async def export_data(
294
+ namespace: str,
295
+ request: Request
296
+ ):
297
+ """
298
+ 导出分析数据
299
+
300
+ Args:
301
+ namespace: 命名空间名称
302
+ """
303
+ try:
304
+ body = await request.json()
305
+ export_format = body.get("format", "csv")
306
+ data_type = body.get("data_type", "tasks")
307
+
308
+ # TODO: 实现数据导出
309
+ return {
310
+ "success": True,
311
+ "data": {
312
+ "export_id": f"export_{namespace}_{datetime.now().strftime('%Y%m%d%H%M%S')}",
313
+ "format": export_format,
314
+ "status": "pending",
315
+ "url": None
316
+ }
317
+ }
318
+ except Exception as e:
319
+ logger.error(f"导出数据失败: {e}")
320
+ raise HTTPException(status_code=500, detail=str(e))
321
+
322
+
323
+ __all__ = ['router']
@@ -0,0 +1,134 @@
1
+ """
2
+ 命名空间管理路由
3
+ 提供命名空间的增删改查和管理功能
4
+ """
5
+ from fastapi import APIRouter, HTTPException, Query
6
+ from typing import Optional, List
7
+ import logging
8
+ import traceback
9
+
10
+ from jettask.schemas import NamespaceCreate, NamespaceUpdate, NamespaceResponse
11
+ from jettask.services.settings_service import SettingsService
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ # 创建独立的命名空间路由,设置 /namespaces 前缀
16
+ router = APIRouter(prefix="/namespaces", tags=["namespaces"])
17
+
18
+
19
+ @router.get("/", response_model=List[NamespaceResponse])
20
+ async def list_namespaces(
21
+ page: int = Query(1, ge=1),
22
+ page_size: int = Query(20, ge=1, le=100),
23
+ is_active: Optional[bool] = None
24
+ ):
25
+ """
26
+ 列出所有命名空间
27
+
28
+ Args:
29
+ page: 页码(从1开始)
30
+ page_size: 每页数量
31
+ is_active: 是否只返回激活的命名空间
32
+ """
33
+ try:
34
+ return await SettingsService.list_namespaces(page, page_size, is_active)
35
+ except Exception as e:
36
+ logger.error(f"获取命名空间列表失败: {e}")
37
+ traceback.print_exc()
38
+ raise HTTPException(status_code=500, detail=str(e))
39
+
40
+
41
+ @router.post("/", response_model=NamespaceResponse, status_code=201)
42
+ async def create_namespace(namespace: NamespaceCreate):
43
+ """
44
+ 创建新的命名空间
45
+
46
+ Args:
47
+ namespace: 命名空间创建信息
48
+ """
49
+ try:
50
+ return await SettingsService.create_namespace(namespace)
51
+ except ValueError as e:
52
+ raise HTTPException(status_code=400, detail=str(e))
53
+ except Exception as e:
54
+ logger.error(f"创建命名空间失败: {e}")
55
+ traceback.print_exc()
56
+ raise HTTPException(status_code=500, detail=str(e))
57
+
58
+
59
+ @router.get("/{namespace_name}", response_model=NamespaceResponse)
60
+ async def get_namespace(namespace_name: str):
61
+ """
62
+ 获取指定命名空间的详细信息
63
+
64
+ Args:
65
+ namespace_name: 命名空间名称
66
+ """
67
+ try:
68
+ return await SettingsService.get_namespace(namespace_name)
69
+ except ValueError as e:
70
+ raise HTTPException(status_code=404, detail=str(e))
71
+ except Exception as e:
72
+ logger.error(f"获取命名空间失败: {e}")
73
+ traceback.print_exc()
74
+ raise HTTPException(status_code=500, detail=str(e))
75
+
76
+
77
+ @router.put("/{namespace_name}", response_model=NamespaceResponse)
78
+ async def update_namespace(namespace_name: str, namespace: NamespaceUpdate):
79
+ """
80
+ 更新命名空间配置
81
+
82
+ Args:
83
+ namespace_name: 命名空间名称
84
+ namespace: 更新的配置信息
85
+ """
86
+ try:
87
+ return await SettingsService.update_namespace(namespace_name, namespace)
88
+ except ValueError as e:
89
+ status_code = 404 if "不存在" in str(e) else 400
90
+ raise HTTPException(status_code=status_code, detail=str(e))
91
+ except Exception as e:
92
+ logger.error(f"更新命名空间失败: {e}")
93
+ traceback.print_exc()
94
+ raise HTTPException(status_code=500, detail=str(e))
95
+
96
+
97
+ @router.delete("/{namespace_name}")
98
+ async def delete_namespace(namespace_name: str):
99
+ """
100
+ 删除命名空间
101
+
102
+ Args:
103
+ namespace_name: 命名空间名称
104
+ """
105
+ try:
106
+ return await SettingsService.delete_namespace(namespace_name)
107
+ except ValueError as e:
108
+ status_code = 400 if "默认命名空间" in str(e) else 404
109
+ raise HTTPException(status_code=status_code, detail=str(e))
110
+ except Exception as e:
111
+ logger.error(f"删除命名空间失败: {e}")
112
+ traceback.print_exc()
113
+ raise HTTPException(status_code=500, detail=str(e))
114
+
115
+
116
+
117
+ @router.get("/{namespace_name}/statistics")
118
+ async def get_namespace_statistics(namespace_name: str):
119
+ """
120
+ 获取命名空间统计信息
121
+
122
+ Args:
123
+ namespace_name: 命名空间名称
124
+ """
125
+ try:
126
+ return await SettingsService.get_namespace_statistics(namespace_name)
127
+ except ValueError as e:
128
+ raise HTTPException(status_code=404, detail=str(e))
129
+ except Exception as e:
130
+ logger.error(f"获取命名空间统计信息失败: {e}")
131
+ traceback.print_exc()
132
+ raise HTTPException(status_code=500, detail=str(e))
133
+
134
+ __all__ = ['router']
@@ -0,0 +1,136 @@
1
+ """
2
+ 概览模块 - 系统总览、健康检查和仪表板统计
3
+ 提供轻量级的路由入口,业务逻辑在 OverviewService 中实现
4
+ """
5
+ from fastapi import APIRouter, HTTPException, Query
6
+ from typing import Optional
7
+ import logging
8
+ import traceback
9
+
10
+ from jettask.schemas import TimeRangeQuery
11
+ from jettask.services.overview_service import OverviewService
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ # 创建概览路由,添加 /overview 前缀
16
+ router = APIRouter(prefix="/overview", tags=["overview"])
17
+
18
+
19
+ # ============ 健康检查和根路径 ============
20
+
21
+ @router.get("/")
22
+ async def root():
23
+ """根路径"""
24
+ return OverviewService.get_root_info()
25
+
26
+
27
+ @router.get("/health")
28
+ async def health_check():
29
+ """健康检查"""
30
+ return OverviewService.get_health_status()
31
+
32
+
33
+ # ============ 系统统计 ============
34
+
35
+ @router.get("/system-stats/{namespace}")
36
+ async def get_system_stats(namespace: str):
37
+ """
38
+ 获取指定命名空间的系统统计信息
39
+
40
+ Args:
41
+ namespace: 命名空间名称
42
+ """
43
+ try:
44
+ return await OverviewService.get_system_stats(namespace)
45
+ except Exception as e:
46
+ logger.error(f"获取系统统计信息失败: {e}")
47
+ traceback.print_exc()
48
+ raise HTTPException(status_code=500, detail=str(e))
49
+
50
+
51
+ # ============ 仪表板统计 ============
52
+
53
+ @router.get("/dashboard-stats/{namespace}")
54
+ async def get_dashboard_stats(
55
+ namespace: str,
56
+ time_range: str = "24h",
57
+ queues: Optional[str] = Query(None, description="逗号分隔的队列名称列表")
58
+ ):
59
+ """
60
+ 获取仪表板统计数据(任务总数、成功数、失败数、成功率、吞吐量等)
61
+
62
+ Args:
63
+ namespace: 命名空间名称
64
+ time_range: 时间范围(如'1h', '24h', '7d')
65
+ queues: 逗号分隔的队列名称列表
66
+ """
67
+ try:
68
+ return await OverviewService.get_dashboard_stats(namespace, time_range, queues)
69
+ except Exception as e:
70
+ logger.error(f"获取仪表板统计数据失败: {e}")
71
+ traceback.print_exc()
72
+ raise HTTPException(status_code=500, detail=str(e))
73
+
74
+
75
+ # ============ 队列排行榜 ============
76
+
77
+ @router.get("/top-queues/{namespace}")
78
+ async def get_top_queues(
79
+ namespace: str,
80
+ metric: str = Query("backlog", description="指标类型: backlog(积压) 或 error(错误率)"),
81
+ limit: int = 10,
82
+ time_range: str = "24h",
83
+ queues: Optional[str] = Query(None, description="逗号分隔的队列名称列表")
84
+ ):
85
+ """
86
+ 获取队列排行榜 - 支持积压和错误率两种指标
87
+
88
+ Args:
89
+ namespace: 命名空间名称
90
+ metric: 指标类型 (backlog/error)
91
+ limit: 返回的队列数量限制
92
+ time_range: 时间范围
93
+ queues: 逗号分隔的队列名称列表
94
+ """
95
+ try:
96
+ return await OverviewService.get_top_queues(namespace, metric, limit, time_range, queues)
97
+ except ValueError as e:
98
+ raise HTTPException(status_code=400, detail=str(e))
99
+ except Exception as e:
100
+ logger.error(f"获取队列排行榜失败: {e}")
101
+ traceback.print_exc()
102
+ raise HTTPException(status_code=500, detail=str(e))
103
+
104
+
105
+
106
+ # ============ 概览统计数据 ============
107
+
108
+ @router.post("/dashboard-overview-stats/{namespace}")
109
+ async def get_dashboard_overview_stats(namespace: str, query: TimeRangeQuery):
110
+ """
111
+ 获取概览页面的统一统计数据
112
+ 包含:任务处理趋势、任务并发数量、任务处理时间、任务执行延时
113
+
114
+ Args:
115
+ namespace: 命名空间名称
116
+ query: 时间范围查询参数
117
+
118
+ Returns:
119
+ 统一的时间序列数据,包含所有概览图表需要的指标和granularity字段
120
+ """
121
+ try:
122
+ return await OverviewService.get_dashboard_overview_stats(namespace, query)
123
+ except Exception as e:
124
+ logger.error(f"获取概览统计数据失败: {e}")
125
+ traceback.print_exc()
126
+ # 返回空数据而不是抛出异常
127
+ return {
128
+ "task_trend": [],
129
+ "concurrency": [],
130
+ "processing_time": [],
131
+ "creation_latency": [],
132
+ "granularity": "minute"
133
+ }
134
+
135
+
136
+ __all__ = ['router']