jettask 0.2.15__py3-none-any.whl → 0.2.17__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 (149) 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 +59 -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/manager.py +6 -0
  32. jettask/scheduler/multi_namespace_scheduler.py +2 -2
  33. jettask/scheduler/unified_manager.py +5 -5
  34. jettask/scheduler/unified_scheduler_manager.py +20 -12
  35. jettask/schemas/__init__.py +166 -0
  36. jettask/schemas/alert.py +99 -0
  37. jettask/schemas/backlog.py +122 -0
  38. jettask/schemas/common.py +139 -0
  39. jettask/schemas/monitoring.py +181 -0
  40. jettask/schemas/namespace.py +168 -0
  41. jettask/schemas/queue.py +83 -0
  42. jettask/schemas/scheduled_task.py +128 -0
  43. jettask/schemas/task.py +70 -0
  44. jettask/services/__init__.py +24 -0
  45. jettask/services/alert_service.py +454 -0
  46. jettask/services/analytics_service.py +46 -0
  47. jettask/services/overview_service.py +978 -0
  48. jettask/services/queue_service.py +711 -0
  49. jettask/services/redis_monitor_service.py +151 -0
  50. jettask/services/scheduled_task_service.py +207 -0
  51. jettask/services/settings_service.py +758 -0
  52. jettask/services/task_service.py +157 -0
  53. jettask/{webui/task_center.py → task_center.py} +30 -8
  54. jettask/{webui/task_center_client.py → task_center_client.py} +1 -1
  55. jettask/{webui/config.py → webui_config.py} +6 -1
  56. jettask/webui_exceptions.py +67 -0
  57. jettask/webui_sql/verify_database.sql +72 -0
  58. {jettask-0.2.15.dist-info → jettask-0.2.17.dist-info}/METADATA +2 -1
  59. jettask-0.2.17.dist-info/RECORD +150 -0
  60. {jettask-0.2.15.dist-info → jettask-0.2.17.dist-info}/entry_points.txt +1 -1
  61. jettask/webui/backend/data_api.py +0 -3294
  62. jettask/webui/backend/namespace_api.py +0 -295
  63. jettask/webui/backend/queue_backlog_api.py +0 -727
  64. jettask/webui/backend/redis_monitor_api.py +0 -476
  65. jettask/webui/frontend/index.html +0 -13
  66. jettask/webui/frontend/package.json +0 -30
  67. jettask/webui/frontend/src/App.css +0 -109
  68. jettask/webui/frontend/src/App.jsx +0 -66
  69. jettask/webui/frontend/src/components/NamespaceSelector.jsx +0 -166
  70. jettask/webui/frontend/src/components/QueueBacklogChart.jsx +0 -298
  71. jettask/webui/frontend/src/components/QueueBacklogTrend.jsx +0 -638
  72. jettask/webui/frontend/src/components/QueueDetailsTable.css +0 -65
  73. jettask/webui/frontend/src/components/QueueDetailsTable.jsx +0 -487
  74. jettask/webui/frontend/src/components/QueueDetailsTableV2.jsx +0 -465
  75. jettask/webui/frontend/src/components/ScheduledTaskFilter.jsx +0 -423
  76. jettask/webui/frontend/src/components/TaskFilter.jsx +0 -425
  77. jettask/webui/frontend/src/components/TimeRangeSelector.css +0 -21
  78. jettask/webui/frontend/src/components/TimeRangeSelector.jsx +0 -160
  79. jettask/webui/frontend/src/components/charts/QueueChart.jsx +0 -111
  80. jettask/webui/frontend/src/components/charts/QueueTrendChart.jsx +0 -115
  81. jettask/webui/frontend/src/components/charts/WorkerChart.jsx +0 -40
  82. jettask/webui/frontend/src/components/common/StatsCard.jsx +0 -18
  83. jettask/webui/frontend/src/components/layout/AppLayout.css +0 -95
  84. jettask/webui/frontend/src/components/layout/AppLayout.jsx +0 -49
  85. jettask/webui/frontend/src/components/layout/Header.css +0 -106
  86. jettask/webui/frontend/src/components/layout/Header.jsx +0 -106
  87. jettask/webui/frontend/src/components/layout/SideMenu.css +0 -137
  88. jettask/webui/frontend/src/components/layout/SideMenu.jsx +0 -209
  89. jettask/webui/frontend/src/components/layout/TabsNav.css +0 -244
  90. jettask/webui/frontend/src/components/layout/TabsNav.jsx +0 -206
  91. jettask/webui/frontend/src/components/layout/UserInfo.css +0 -197
  92. jettask/webui/frontend/src/components/layout/UserInfo.jsx +0 -197
  93. jettask/webui/frontend/src/contexts/LoadingContext.jsx +0 -27
  94. jettask/webui/frontend/src/contexts/NamespaceContext.jsx +0 -72
  95. jettask/webui/frontend/src/contexts/TabsContext.backup.jsx +0 -245
  96. jettask/webui/frontend/src/index.css +0 -114
  97. jettask/webui/frontend/src/main.jsx +0 -22
  98. jettask/webui/frontend/src/pages/Alerts.jsx +0 -684
  99. jettask/webui/frontend/src/pages/Dashboard/index.css +0 -35
  100. jettask/webui/frontend/src/pages/Dashboard/index.jsx +0 -281
  101. jettask/webui/frontend/src/pages/Dashboard.jsx +0 -1330
  102. jettask/webui/frontend/src/pages/QueueDetail.jsx +0 -1117
  103. jettask/webui/frontend/src/pages/QueueMonitor.jsx +0 -527
  104. jettask/webui/frontend/src/pages/Queues.jsx +0 -12
  105. jettask/webui/frontend/src/pages/ScheduledTasks.jsx +0 -810
  106. jettask/webui/frontend/src/pages/Settings.jsx +0 -801
  107. jettask/webui/frontend/src/pages/Workers.jsx +0 -12
  108. jettask/webui/frontend/src/services/api.js +0 -159
  109. jettask/webui/frontend/src/services/queueTrend.js +0 -166
  110. jettask/webui/frontend/src/utils/suppressWarnings.js +0 -22
  111. jettask/webui/frontend/src/utils/userPreferences.js +0 -154
  112. jettask/webui/frontend/vite.config.js +0 -26
  113. jettask/webui/sql/init_database.sql +0 -640
  114. jettask-0.2.15.dist-info/RECORD +0 -172
  115. /jettask/{webui/backend → backend}/__init__.py +0 -0
  116. /jettask/{webui/backend → backend}/api/__init__.py +0 -0
  117. /jettask/{webui/backend → backend}/api/v1/__init__.py +0 -0
  118. /jettask/{webui/backend → backend}/api/v1/monitoring.py +0 -0
  119. /jettask/{webui/backend → backend}/api/v1/namespaces.py +0 -0
  120. /jettask/{webui/backend → backend}/api/v1/queues.py +0 -0
  121. /jettask/{webui/backend → backend}/api/v1/tasks.py +0 -0
  122. /jettask/{webui/backend → backend}/config.py +0 -0
  123. /jettask/{webui/backend → backend}/core/__init__.py +0 -0
  124. /jettask/{webui/backend → backend}/core/cache.py +0 -0
  125. /jettask/{webui/backend → backend}/core/database.py +0 -0
  126. /jettask/{webui/backend → backend}/core/exceptions.py +0 -0
  127. /jettask/{webui/backend → backend}/data_access.py +0 -0
  128. /jettask/{webui/backend → backend}/dependencies.py +0 -0
  129. /jettask/{webui/backend → backend}/init_meta_db.py +0 -0
  130. /jettask/{webui/backend → backend}/main_v2.py +0 -0
  131. /jettask/{webui/backend → backend}/models/__init__.py +0 -0
  132. /jettask/{webui/backend → backend}/models/requests.py +0 -0
  133. /jettask/{webui/backend → backend}/models/responses.py +0 -0
  134. /jettask/{webui/backend → backend}/queue_stats_v2.py +0 -0
  135. /jettask/{webui/backend → backend}/services/__init__.py +0 -0
  136. /jettask/{webui/backend → backend}/start.py +0 -0
  137. /jettask/{webui/cleanup_deprecated_tables.sql → cleanup_deprecated_tables.sql} +0 -0
  138. /jettask/{webui/gradio_app.py → gradio_app.py} +0 -0
  139. /jettask/{webui/__init__.py → main.py} +0 -0
  140. /jettask/{webui/models.py → models.py} +0 -0
  141. /jettask/{webui/run_monitor.py → run_monitor.py} +0 -0
  142. /jettask/{webui/schema.sql → schema.sql} +0 -0
  143. /jettask/{webui/unified_consumer_manager.py → unified_consumer_manager.py} +0 -0
  144. /jettask/{webui/models → webui_models}/__init__.py +0 -0
  145. /jettask/{webui/models → webui_models}/namespace.py +0 -0
  146. /jettask/{webui/sql → webui_sql}/batch_upsert_functions.sql +0 -0
  147. {jettask-0.2.15.dist-info → jettask-0.2.17.dist-info}/WHEEL +0 -0
  148. {jettask-0.2.15.dist-info → jettask-0.2.17.dist-info}/licenses/LICENSE +0 -0
  149. {jettask-0.2.15.dist-info → jettask-0.2.17.dist-info}/top_level.txt +0 -0
@@ -1,295 +0,0 @@
1
- """
2
- 命名空间管理API - 重构版本
3
- 使用数据库持久化命名空间数据,使用名称作为路径参数
4
- """
5
- from fastapi import APIRouter, HTTPException, Query
6
- from pydantic import BaseModel
7
- from typing import Dict, Any, Optional, List
8
- from datetime import datetime
9
- import json
10
- from sqlalchemy import text
11
- import logging
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
- router = APIRouter(prefix="/api/namespaces", tags=["namespaces"])
16
-
17
- # 使用任务中心专用的元数据库连接
18
- from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
19
- from sqlalchemy.orm import sessionmaker
20
- from jettask.webui.backend.config import task_center_config
21
- import traceback
22
-
23
- # 创建异步引擎 - 连接到任务中心元数据库
24
- # 注意:这是任务中心自己的数据库,不是JetTask应用的数据库
25
- engine = create_async_engine(task_center_config.meta_database_url, echo=False)
26
- AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
27
-
28
-
29
- class NamespaceCreate(BaseModel):
30
- """创建命名空间请求"""
31
- name: str
32
- description: Optional[str] = None
33
- redis_config: Dict[str, Any]
34
- pg_config: Dict[str, Any]
35
-
36
-
37
- class NamespaceUpdate(BaseModel):
38
- """更新命名空间请求"""
39
- description: Optional[str] = None
40
- redis_config: Optional[Dict[str, Any]] = None
41
- pg_config: Optional[Dict[str, Any]] = None
42
- is_active: Optional[bool] = None
43
-
44
-
45
- class NamespaceResponse(BaseModel):
46
- """命名空间响应"""
47
- id: int # 自增整数ID
48
- name: str
49
- description: Optional[str]
50
- redis_config: Dict[str, Any]
51
- pg_config: Dict[str, Any]
52
- is_active: bool
53
- version: int # 版本号
54
- created_at: datetime
55
- updated_at: datetime
56
- connection_url: str
57
-
58
-
59
- @router.get("", response_model=List[NamespaceResponse])
60
- async def list_namespaces(
61
- page: int = Query(1, ge=1),
62
- page_size: int = Query(20, ge=1, le=100),
63
- is_active: Optional[bool] = None
64
- ):
65
- """列出所有命名空间"""
66
- try:
67
- async with AsyncSessionLocal() as session:
68
- query = """
69
- SELECT id, name, description, redis_config, pg_config,
70
- is_active, version, created_at, updated_at
71
- FROM namespaces
72
- """
73
- params = {}
74
-
75
- if is_active is not None:
76
- query += " WHERE is_active = :is_active"
77
- params['is_active'] = is_active
78
-
79
- query += " ORDER BY created_at DESC"
80
- query += " LIMIT :limit OFFSET :offset"
81
- params['limit'] = page_size
82
- params['offset'] = (page - 1) * page_size
83
-
84
- result = await session.execute(text(query), params)
85
- rows = result.fetchall()
86
-
87
- namespaces = []
88
- for row in rows:
89
- namespaces.append(NamespaceResponse(
90
- id=row.id,
91
- name=row.name,
92
- description=row.description,
93
- redis_config=row.redis_config,
94
- pg_config=row.pg_config,
95
- is_active=row.is_active,
96
- version=row.version,
97
- created_at=row.created_at,
98
- updated_at=row.updated_at,
99
- connection_url=f"/api/namespaces/{row.name}" # 使用名称
100
- ))
101
-
102
- return namespaces
103
- except Exception as e:
104
- logger.error(f"Failed to list namespaces: {e}")
105
- traceback.print_exc()
106
- raise HTTPException(status_code=500, detail=str(e))
107
-
108
-
109
- @router.post("", response_model=NamespaceResponse, status_code=201)
110
- async def create_namespace(namespace: NamespaceCreate):
111
- """创建新的命名空间"""
112
- try:
113
- async with AsyncSessionLocal() as session:
114
- # 检查名称是否已存在
115
- check_query = text("SELECT COUNT(*) FROM namespaces WHERE name = :name")
116
- result = await session.execute(check_query, {'name': namespace.name})
117
- if result.scalar() > 0:
118
- raise HTTPException(status_code=400, detail=f"命名空间 '{namespace.name}' 已存在")
119
-
120
- # 创建命名空间(使用自增ID)
121
- insert_query = text("""
122
- INSERT INTO namespaces (name, description, redis_config, pg_config, version)
123
- VALUES (:name, :description, :redis_config, :pg_config, 1)
124
- RETURNING id, name, description, redis_config, pg_config,
125
- is_active, version, created_at, updated_at
126
- """)
127
-
128
- result = await session.execute(insert_query, {
129
- 'name': namespace.name,
130
- 'description': namespace.description,
131
- 'redis_config': json.dumps(namespace.redis_config),
132
- 'pg_config': json.dumps(namespace.pg_config)
133
- })
134
-
135
- row = result.fetchone()
136
- await session.commit()
137
-
138
- return NamespaceResponse(
139
- id=row.id,
140
- name=row.name,
141
- description=row.description,
142
- redis_config=row.redis_config,
143
- pg_config=row.pg_config,
144
- is_active=row.is_active,
145
- version=row.version,
146
- created_at=row.created_at,
147
- updated_at=row.updated_at,
148
- connection_url=f"/api/namespaces/{row.name}" # 使用名称
149
- )
150
- except HTTPException:
151
- raise
152
- except Exception as e:
153
- logger.error(f"Failed to create namespace: {e}")
154
- traceback.print_exc()
155
- raise HTTPException(status_code=500, detail=str(e))
156
-
157
-
158
- @router.get("/{namespace_name}", response_model=NamespaceResponse)
159
- async def get_namespace(namespace_name: str):
160
- """获取指定命名空间的详细信息"""
161
- try:
162
- async with AsyncSessionLocal() as session:
163
- query = text("""
164
- SELECT id, name, description, redis_config, pg_config,
165
- is_active, version, created_at, updated_at
166
- FROM namespaces
167
- WHERE name = :name
168
- """)
169
-
170
- result = await session.execute(query, {'name': namespace_name})
171
- row = result.fetchone()
172
-
173
- if not row:
174
- raise HTTPException(status_code=404, detail="命名空间不存在")
175
-
176
- return NamespaceResponse(
177
- id=row.id,
178
- name=row.name,
179
- description=row.description,
180
- redis_config=row.redis_config,
181
- pg_config=row.pg_config,
182
- is_active=row.is_active,
183
- version=row.version,
184
- created_at=row.created_at,
185
- updated_at=row.updated_at,
186
- connection_url=f"/api/namespaces/{row.name}" # 使用名称
187
- )
188
- except HTTPException:
189
- raise
190
- except Exception as e:
191
- logger.error(f"Failed to get namespace: {e}")
192
- traceback.print_exc()
193
- raise HTTPException(status_code=500, detail=str(e))
194
-
195
-
196
- @router.put("/{namespace_name}", response_model=NamespaceResponse)
197
- async def update_namespace(namespace_name: str, namespace: NamespaceUpdate):
198
- """更新命名空间"""
199
- try:
200
- async with AsyncSessionLocal() as session:
201
- # 检查是否存在
202
- check_query = text("SELECT id, name FROM namespaces WHERE name = :name")
203
- result = await session.execute(check_query, {'name': namespace_name})
204
- row = result.fetchone()
205
-
206
- if not row:
207
- raise HTTPException(status_code=404, detail="命名空间不存在")
208
-
209
- # 构建更新语句
210
- updates = []
211
- params = {'name': namespace_name}
212
-
213
- if namespace.description is not None:
214
- updates.append("description = :description")
215
- params['description'] = namespace.description
216
-
217
- if namespace.redis_config is not None:
218
- updates.append("redis_config = :redis_config")
219
- params['redis_config'] = json.dumps(namespace.redis_config)
220
-
221
- if namespace.pg_config is not None:
222
- updates.append("pg_config = :pg_config")
223
- params['pg_config'] = json.dumps(namespace.pg_config)
224
-
225
- if namespace.is_active is not None:
226
- updates.append("is_active = :is_active")
227
- params['is_active'] = namespace.is_active
228
-
229
- if not updates:
230
- raise HTTPException(status_code=400, detail="没有要更新的字段")
231
-
232
- # 如果更新了redis_config或pg_config,递增版本号
233
- if 'redis_config' in params or 'pg_config' in params:
234
- updates.append("version = version + 1")
235
-
236
- update_query = text(f"""
237
- UPDATE namespaces
238
- SET {', '.join(updates)}
239
- WHERE name = :name
240
- RETURNING id, name, description, redis_config, pg_config,
241
- is_active, version, created_at, updated_at
242
- """)
243
-
244
- result = await session.execute(update_query, params)
245
- row = result.fetchone()
246
- await session.commit()
247
-
248
- return NamespaceResponse(
249
- id=row.id,
250
- name=row.name,
251
- description=row.description,
252
- redis_config=row.redis_config,
253
- pg_config=row.pg_config,
254
- is_active=row.is_active,
255
- version=row.version,
256
- created_at=row.created_at,
257
- updated_at=row.updated_at,
258
- connection_url=f"/api/namespaces/{row.name}" # 使用名称
259
- )
260
- except HTTPException:
261
- raise
262
- except Exception as e:
263
- logger.error(f"Failed to update namespace: {e}")
264
- traceback.print_exc()
265
- raise HTTPException(status_code=500, detail=str(e))
266
-
267
-
268
- @router.delete("/{namespace_name}")
269
- async def delete_namespace(namespace_name: str):
270
- """删除命名空间"""
271
- try:
272
- async with AsyncSessionLocal() as session:
273
- # 检查是否为默认命名空间
274
- if namespace_name == 'default':
275
- raise HTTPException(status_code=400, detail="不能删除默认命名空间")
276
-
277
- check_query = text("SELECT name FROM namespaces WHERE name = :name")
278
- result = await session.execute(check_query, {'name': namespace_name})
279
- row = result.fetchone()
280
-
281
- if not row:
282
- raise HTTPException(status_code=404, detail="命名空间不存在")
283
-
284
- # 删除命名空间
285
- delete_query = text("DELETE FROM namespaces WHERE name = :name")
286
- await session.execute(delete_query, {'name': namespace_name})
287
- await session.commit()
288
-
289
- return {"message": "命名空间已删除"}
290
- except HTTPException:
291
- raise
292
- except Exception as e:
293
- logger.error(f"Failed to delete namespace: {e}")
294
- traceback.print_exc()
295
- raise HTTPException(status_code=500, detail=str(e))