jettask 0.2.23__py3-none-any.whl → 0.2.24__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 (110) hide show
  1. jettask/__init__.py +2 -0
  2. jettask/cli.py +12 -8
  3. jettask/config/lua_scripts.py +37 -0
  4. jettask/config/nacos_config.py +1 -1
  5. jettask/core/app.py +313 -340
  6. jettask/core/container.py +4 -4
  7. jettask/{persistence → core}/namespace.py +93 -27
  8. jettask/core/task.py +16 -9
  9. jettask/core/unified_manager_base.py +136 -26
  10. jettask/db/__init__.py +67 -0
  11. jettask/db/base.py +137 -0
  12. jettask/{utils/db_connector.py → db/connector.py} +130 -26
  13. jettask/db/models/__init__.py +16 -0
  14. jettask/db/models/scheduled_task.py +196 -0
  15. jettask/db/models/task.py +77 -0
  16. jettask/db/models/task_run.py +85 -0
  17. jettask/executor/__init__.py +0 -15
  18. jettask/executor/core.py +76 -31
  19. jettask/executor/process_entry.py +29 -114
  20. jettask/executor/task_executor.py +4 -0
  21. jettask/messaging/event_pool.py +928 -685
  22. jettask/messaging/scanner.py +30 -0
  23. jettask/persistence/__init__.py +28 -103
  24. jettask/persistence/buffer.py +170 -0
  25. jettask/persistence/consumer.py +330 -249
  26. jettask/persistence/manager.py +304 -0
  27. jettask/persistence/persistence.py +391 -0
  28. jettask/scheduler/__init__.py +15 -3
  29. jettask/scheduler/{task_crud.py → database.py} +61 -57
  30. jettask/scheduler/loader.py +2 -2
  31. jettask/scheduler/{scheduler_coordinator.py → manager.py} +23 -6
  32. jettask/scheduler/models.py +14 -10
  33. jettask/scheduler/schedule.py +166 -0
  34. jettask/scheduler/scheduler.py +12 -11
  35. jettask/schemas/__init__.py +50 -1
  36. jettask/schemas/backlog.py +43 -6
  37. jettask/schemas/namespace.py +70 -19
  38. jettask/schemas/queue.py +19 -3
  39. jettask/schemas/responses.py +493 -0
  40. jettask/task/__init__.py +0 -2
  41. jettask/task/router.py +3 -0
  42. jettask/test_connection_monitor.py +1 -1
  43. jettask/utils/__init__.py +7 -5
  44. jettask/utils/db_init.py +8 -4
  45. jettask/utils/namespace_dep.py +167 -0
  46. jettask/utils/queue_matcher.py +186 -0
  47. jettask/utils/rate_limit/concurrency_limiter.py +7 -1
  48. jettask/utils/stream_backlog.py +1 -1
  49. jettask/webui/__init__.py +0 -1
  50. jettask/webui/api/__init__.py +4 -4
  51. jettask/webui/api/alerts.py +806 -71
  52. jettask/webui/api/example_refactored.py +400 -0
  53. jettask/webui/api/namespaces.py +390 -45
  54. jettask/webui/api/overview.py +300 -54
  55. jettask/webui/api/queues.py +971 -267
  56. jettask/webui/api/scheduled.py +1249 -56
  57. jettask/webui/api/settings.py +129 -7
  58. jettask/webui/api/workers.py +442 -0
  59. jettask/webui/app.py +46 -2329
  60. jettask/webui/middleware/__init__.py +6 -0
  61. jettask/webui/middleware/namespace_middleware.py +135 -0
  62. jettask/webui/services/__init__.py +146 -0
  63. jettask/webui/services/heartbeat_service.py +251 -0
  64. jettask/webui/services/overview_service.py +60 -51
  65. jettask/webui/services/queue_monitor_service.py +426 -0
  66. jettask/webui/services/redis_monitor_service.py +87 -0
  67. jettask/webui/services/settings_service.py +174 -111
  68. jettask/webui/services/task_monitor_service.py +222 -0
  69. jettask/webui/services/timeline_pg_service.py +452 -0
  70. jettask/webui/services/timeline_service.py +189 -0
  71. jettask/webui/services/worker_monitor_service.py +467 -0
  72. jettask/webui/utils/__init__.py +11 -0
  73. jettask/webui/utils/time_utils.py +122 -0
  74. jettask/worker/lifecycle.py +8 -2
  75. {jettask-0.2.23.dist-info → jettask-0.2.24.dist-info}/METADATA +1 -1
  76. jettask-0.2.24.dist-info/RECORD +142 -0
  77. jettask/executor/executor.py +0 -338
  78. jettask/persistence/backlog_monitor.py +0 -567
  79. jettask/persistence/base.py +0 -2334
  80. jettask/persistence/db_manager.py +0 -516
  81. jettask/persistence/maintenance.py +0 -81
  82. jettask/persistence/message_consumer.py +0 -259
  83. jettask/persistence/models.py +0 -49
  84. jettask/persistence/offline_recovery.py +0 -196
  85. jettask/persistence/queue_discovery.py +0 -215
  86. jettask/persistence/task_persistence.py +0 -218
  87. jettask/persistence/task_updater.py +0 -583
  88. jettask/scheduler/add_execution_count.sql +0 -11
  89. jettask/scheduler/add_priority_field.sql +0 -26
  90. jettask/scheduler/add_scheduler_id.sql +0 -25
  91. jettask/scheduler/add_scheduler_id_index.sql +0 -10
  92. jettask/scheduler/make_scheduler_id_required.sql +0 -28
  93. jettask/scheduler/migrate_interval_seconds.sql +0 -9
  94. jettask/scheduler/performance_optimization.sql +0 -45
  95. jettask/scheduler/run_scheduler.py +0 -186
  96. jettask/scheduler/schema.sql +0 -84
  97. jettask/task/task_executor.py +0 -318
  98. jettask/webui/api/analytics.py +0 -323
  99. jettask/webui/config.py +0 -90
  100. jettask/webui/models/__init__.py +0 -3
  101. jettask/webui/models/namespace.py +0 -63
  102. jettask/webui/namespace_manager/__init__.py +0 -10
  103. jettask/webui/namespace_manager/multi.py +0 -593
  104. jettask/webui/namespace_manager/unified.py +0 -193
  105. jettask/webui/run.py +0 -46
  106. jettask-0.2.23.dist-info/RECORD +0 -145
  107. {jettask-0.2.23.dist-info → jettask-0.2.24.dist-info}/WHEEL +0 -0
  108. {jettask-0.2.23.dist-info → jettask-0.2.24.dist-info}/entry_points.txt +0 -0
  109. {jettask-0.2.23.dist-info → jettask-0.2.24.dist-info}/licenses/LICENSE +0 -0
  110. {jettask-0.2.23.dist-info → jettask-0.2.24.dist-info}/top_level.txt +0 -0
@@ -2,12 +2,12 @@
2
2
  命名空间管理路由
3
3
  提供命名空间的增删改查和管理功能
4
4
  """
5
- from fastapi import APIRouter, HTTPException, Query
6
- from typing import Optional, List
5
+ from fastapi import APIRouter, HTTPException, Query, Path
6
+ from typing import Optional, List, Dict, Any
7
7
  import logging
8
8
  import traceback
9
9
 
10
- from jettask.schemas import NamespaceCreate, NamespaceUpdate, NamespaceResponse
10
+ from jettask.schemas import NamespaceCreate, NamespaceUpdate, NamespaceResponse, NamespaceStatisticsResponse
11
11
  from jettask.webui.services.settings_service import SettingsService
12
12
 
13
13
  logger = logging.getLogger(__name__)
@@ -16,19 +16,57 @@ logger = logging.getLogger(__name__)
16
16
  router = APIRouter(prefix="/namespaces", tags=["namespaces"])
17
17
 
18
18
 
19
- @router.get("/", response_model=List[NamespaceResponse])
19
+ @router.get(
20
+ "/",
21
+ summary="列出所有命名空间",
22
+ description="获取系统中所有命名空间的列表,支持分页和按状态筛选",
23
+ response_model=List[NamespaceResponse],
24
+ responses={
25
+ 200: {
26
+ "description": "成功返回命名空间列表"
27
+ },
28
+ 500: {
29
+ "description": "服务器内部错误",
30
+ "content": {
31
+ "application/json": {
32
+ "example": {"detail": "获取命名空间列表失败: Database error"}
33
+ }
34
+ }
35
+ }
36
+ }
37
+ )
20
38
  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
- ):
39
+ page: int = Query(1, ge=1, description="页码,从 1 开始", example=1),
40
+ page_size: int = Query(20, ge=1, le=100, description="每页数量,范围 1-100", example=20),
41
+ is_active: Optional[bool] = Query(None, description="是否只返回激活的命名空间", example=True)
42
+ ) -> List[Dict[str, Any]]:
25
43
  """
26
- 列出所有命名空间
27
-
28
- Args:
29
- page: 页码(从1开始)
30
- page_size: 每页数量
31
- is_active: 是否只返回激活的命名空间
44
+ ## 列出所有命名空间
45
+
46
+ 获取系统中所有命名空间的列表,每个命名空间包含配置信息和连接状态。
47
+
48
+ **功能说明**:
49
+ - 支持分页查询,避免一次返回过多数据
50
+ - 可按激活状态筛选命名空间
51
+ - 返回每个命名空间的完整配置信息
52
+
53
+ **使用场景**:
54
+ - 命名空间管理页面
55
+ - 环境切换选择列表
56
+ - 系统配置概览
57
+
58
+ **示例请求**:
59
+ ```bash
60
+ # 获取第一页的命名空间列表
61
+ curl -X GET "http://localhost:8001/api/v1/namespaces/?page=1&page_size=20"
62
+
63
+ # 只获取激活的命名空间
64
+ curl -X GET "http://localhost:8001/api/v1/namespaces/?is_active=true"
65
+ ```
66
+
67
+ **注意事项**:
68
+ - 返回的 Redis 和 PostgreSQL URL 会隐藏密码信息
69
+ - 分页参数超出范围时返回空列表
32
70
  """
33
71
  try:
34
72
  return await SettingsService.list_namespaces(page, page_size, is_active)
@@ -38,13 +76,87 @@ async def list_namespaces(
38
76
  raise HTTPException(status_code=500, detail=str(e))
39
77
 
40
78
 
41
- @router.post("/", response_model=NamespaceResponse, status_code=201)
42
- async def create_namespace(namespace: NamespaceCreate):
79
+ @router.post(
80
+ "/",
81
+ summary="创建新的命名空间",
82
+ description="创建一个新的命名空间,可以选择直接配置或使用 Nacos 配置",
83
+ response_model=NamespaceResponse,
84
+ status_code=201,
85
+ responses={
86
+ 201: {
87
+ "description": "命名空间创建成功"
88
+ },
89
+ 400: {
90
+ "description": "请求参数错误",
91
+ "content": {
92
+ "application/json": {
93
+ "example": {"detail": "命名空间名称已存在"}
94
+ }
95
+ }
96
+ },
97
+ 500: {
98
+ "description": "服务器内部错误"
99
+ }
100
+ }
101
+ )
102
+ async def create_namespace(
103
+ namespace: NamespaceCreate
104
+ ) -> Dict[str, Any]:
43
105
  """
44
- 创建新的命名空间
45
-
46
- Args:
47
- namespace: 命名空间创建信息
106
+ ## 创建新的命名空间
107
+
108
+ 创建一个新的命名空间,用于隔离不同环境或项目的任务队列。
109
+
110
+ **配置模式**:
111
+ 1. **direct 模式**: 直接提供 Redis 和 PostgreSQL 连接字符串
112
+ 2. **nacos 模式**: 通过 Nacos 配置键获取连接字符串
113
+
114
+ **请求体参数**:
115
+ ```json
116
+ {
117
+ "name": "production",
118
+ "description": "生产环境命名空间",
119
+ "config_mode": "direct",
120
+ "redis_url": "redis://:password@localhost:6379/0",
121
+ "pg_url": "postgresql://user:password@localhost:5432/jettask"
122
+ }
123
+ ```
124
+
125
+ **使用场景**:
126
+ - 创建新的环境隔离(如 dev、staging、production)
127
+ - 多项目隔离
128
+ - 多租户场景
129
+
130
+ **示例请求**:
131
+ ```bash
132
+ # 使用直接配置模式
133
+ curl -X POST "http://localhost:8001/api/v1/namespaces/" \\
134
+ -H "Content-Type: application/json" \\
135
+ -d '{
136
+ "name": "production",
137
+ "description": "生产环境",
138
+ "config_mode": "direct",
139
+ "redis_url": "redis://:password@localhost:6379/0",
140
+ "pg_url": "postgresql://user:password@localhost:5432/jettask"
141
+ }'
142
+
143
+ # 使用 Nacos 配置模式
144
+ curl -X POST "http://localhost:8001/api/v1/namespaces/" \\
145
+ -H "Content-Type: application/json" \\
146
+ -d '{
147
+ "name": "staging",
148
+ "description": "预发布环境",
149
+ "config_mode": "nacos",
150
+ "redis_nacos_key": "staging.redis.url",
151
+ "pg_nacos_key": "staging.pg.url"
152
+ }'
153
+ ```
154
+
155
+ **注意事项**:
156
+ - 命名空间名称必须唯一
157
+ - Redis 连接字符串格式: `redis://[password@]host:port/db`
158
+ - PostgreSQL 连接字符串格式: `postgresql://user:password@host:port/database`
159
+ - 创建后会自动验证连接是否可用
48
160
  """
49
161
  try:
50
162
  return await SettingsService.create_namespace(namespace)
@@ -56,13 +168,57 @@ async def create_namespace(namespace: NamespaceCreate):
56
168
  raise HTTPException(status_code=500, detail=str(e))
57
169
 
58
170
 
59
- @router.get("/{namespace_name}", response_model=NamespaceResponse)
60
- async def get_namespace(namespace_name: str):
171
+ @router.get(
172
+ "/{namespace_name}",
173
+ summary="获取命名空间详细信息",
174
+ description="获取指定命名空间的完整配置信息和状态",
175
+ response_model=NamespaceResponse,
176
+ responses={
177
+ 200: {
178
+ "description": "成功返回命名空间详情"
179
+ },
180
+ 404: {
181
+ "description": "命名空间不存在",
182
+ "content": {
183
+ "application/json": {
184
+ "example": {"detail": "命名空间 'production' 不存在"}
185
+ }
186
+ }
187
+ },
188
+ 500: {
189
+ "description": "服务器内部错误"
190
+ }
191
+ }
192
+ )
193
+ async def get_namespace(
194
+ namespace_name: str = Path(..., description="命名空间名称", example="default")
195
+ ) -> Dict[str, Any]:
61
196
  """
62
- 获取指定命名空间的详细信息
63
-
64
- Args:
65
- namespace_name: 命名空间名称
197
+ ## 获取命名空间详细信息
198
+
199
+ 获取指定命名空间的完整配置信息,包括 Redis、PostgreSQL 配置和连接状态。
200
+
201
+ **返回信息包括**:
202
+ - 命名空间基本信息(名称、描述、启用状态)
203
+ - Redis 连接配置
204
+ - PostgreSQL 连接配置
205
+ - 连接 URL
206
+ - 配置版本号
207
+ - 创建和更新时间
208
+
209
+ **使用场景**:
210
+ - 查看命名空间详细配置
211
+ - 验证命名空间设置
212
+ - 配置管理界面
213
+
214
+ **示例请求**:
215
+ ```bash
216
+ curl -X GET "http://localhost:8001/api/v1/namespaces/default"
217
+ ```
218
+
219
+ **注意事项**:
220
+ - 返回的连接字符串会隐藏敏感信息(如密码)
221
+ - 如果命名空间不存在,返回 404 错误
66
222
  """
67
223
  try:
68
224
  return await SettingsService.get_namespace(namespace_name)
@@ -74,14 +230,88 @@ async def get_namespace(namespace_name: str):
74
230
  raise HTTPException(status_code=500, detail=str(e))
75
231
 
76
232
 
77
- @router.put("/{namespace_name}", response_model=NamespaceResponse)
78
- async def update_namespace(namespace_name: str, namespace: NamespaceUpdate):
233
+ @router.put(
234
+ "/{namespace_name}",
235
+ summary="更新命名空间配置",
236
+ description="更新指定命名空间的配置信息,支持部分更新",
237
+ response_model=NamespaceResponse,
238
+ responses={
239
+ 200: {
240
+ "description": "命名空间更新成功"
241
+ },
242
+ 400: {
243
+ "description": "请求参数错误",
244
+ "content": {
245
+ "application/json": {
246
+ "example": {"detail": "配置参数无效"}
247
+ }
248
+ }
249
+ },
250
+ 404: {
251
+ "description": "命名空间不存在",
252
+ "content": {
253
+ "application/json": {
254
+ "example": {"detail": "命名空间 'production' 不存在"}
255
+ }
256
+ }
257
+ },
258
+ 500: {
259
+ "description": "服务器内部错误"
260
+ }
261
+ }
262
+ )
263
+ async def update_namespace(
264
+ namespace_name: str = Path(..., description="命名空间名称", example="default"),
265
+ namespace: NamespaceUpdate = ...
266
+ ) -> Dict[str, Any]:
79
267
  """
80
- 更新命名空间配置
81
-
82
- Args:
83
- namespace_name: 命名空间名称
84
- namespace: 更新的配置信息
268
+ ## 更新命名空间配置
269
+
270
+ 更新指定命名空间的配置信息,所有字段都是可选的,只更新提供的字段。
271
+
272
+ **可更新的字段**:
273
+ - 描述信息
274
+ - 配置模式(direct/nacos)
275
+ - Redis 连接配置
276
+ - PostgreSQL 连接配置
277
+ - 启用状态
278
+
279
+ **请求体参数**:
280
+ ```json
281
+ {
282
+ "description": "更新后的描述",
283
+ "enabled": true
284
+ }
285
+ ```
286
+
287
+ **使用场景**:
288
+ - 修改命名空间描述
289
+ - 更新连接配置
290
+ - 启用或禁用命名空间
291
+
292
+ **示例请求**:
293
+ ```bash
294
+ # 更新描述和状态
295
+ curl -X PUT "http://localhost:8001/api/v1/namespaces/default" \\
296
+ -H "Content-Type: application/json" \\
297
+ -d '{
298
+ "description": "默认命名空间(已更新)",
299
+ "enabled": true
300
+ }'
301
+
302
+ # 更新 Redis 配置
303
+ curl -X PUT "http://localhost:8001/api/v1/namespaces/production" \\
304
+ -H "Content-Type: application/json" \\
305
+ -d '{
306
+ "config_mode": "direct",
307
+ "redis_url": "redis://:newpassword@localhost:6380/1"
308
+ }'
309
+ ```
310
+
311
+ **注意事项**:
312
+ - 更新配置后会自动验证新的连接是否可用
313
+ - 如果有任务正在处理,建议谨慎更新
314
+ - 只提供需要更新的字段,未提供的字段保持不变
85
315
  """
86
316
  try:
87
317
  return await SettingsService.update_namespace(namespace_name, namespace)
@@ -94,13 +324,68 @@ async def update_namespace(namespace_name: str, namespace: NamespaceUpdate):
94
324
  raise HTTPException(status_code=500, detail=str(e))
95
325
 
96
326
 
97
- @router.delete("/{namespace_name}")
98
- async def delete_namespace(namespace_name: str):
327
+ @router.delete(
328
+ "/{namespace_name}",
329
+ summary="删除命名空间",
330
+ description="删除指定的命名空间,默认命名空间不能删除",
331
+ responses={
332
+ 200: {
333
+ "description": "命名空间删除成功",
334
+ "content": {
335
+ "application/json": {
336
+ "example": {"success": True, "message": "命名空间已删除"}
337
+ }
338
+ }
339
+ },
340
+ 400: {
341
+ "description": "操作不允许",
342
+ "content": {
343
+ "application/json": {
344
+ "example": {"detail": "默认命名空间不能删除"}
345
+ }
346
+ }
347
+ },
348
+ 404: {
349
+ "description": "命名空间不存在",
350
+ "content": {
351
+ "application/json": {
352
+ "example": {"detail": "命名空间 'production' 不存在"}
353
+ }
354
+ }
355
+ },
356
+ 500: {
357
+ "description": "服务器内部错误"
358
+ }
359
+ }
360
+ )
361
+ async def delete_namespace(
362
+ namespace_name: str = Path(..., description="命名空间名称", example="staging")
363
+ ) -> Dict[str, Any]:
99
364
  """
100
- 删除命名空间
101
-
102
- Args:
103
- namespace_name: 命名空间名称
365
+ ## 删除命名空间
366
+
367
+ 删除指定的命名空间及其所有相关配置。
368
+
369
+ **删除规则**:
370
+ - 默认命名空间(default)不能删除
371
+ - 删除前会检查是否还有活跃的任务
372
+ - 删除操作不可逆,请谨慎操作
373
+
374
+ **使用场景**:
375
+ - 清理不再使用的环境
376
+ - 移除测试命名空间
377
+ - 环境下线
378
+
379
+ **示例请求**:
380
+ ```bash
381
+ curl -X DELETE "http://localhost:8001/api/v1/namespaces/staging"
382
+ ```
383
+
384
+ **注意事项**:
385
+ - 删除命名空间会清除该命名空间下的所有配置
386
+ - 不会删除 Redis 和 PostgreSQL 中的实际数据
387
+ - 建议删除前先备份重要数据
388
+ - 如果有任务正在处理,删除操作可能会失败
104
389
  """
105
390
  try:
106
391
  return await SettingsService.delete_namespace(namespace_name)
@@ -114,13 +399,73 @@ async def delete_namespace(namespace_name: str):
114
399
 
115
400
 
116
401
 
117
- @router.get("/{namespace_name}/statistics")
118
- async def get_namespace_statistics(namespace_name: str):
402
+ @router.get(
403
+ "/{namespace_name}/statistics",
404
+ summary="获取命名空间统计信息",
405
+ description="获取指定命名空间的统计数据,包括队列数、任务数、Worker 数等",
406
+ response_model=NamespaceStatisticsResponse,
407
+ responses={
408
+ 200: {
409
+ "description": "成功返回统计信息"
410
+ },
411
+ 404: {
412
+ "description": "命名空间不存在",
413
+ "content": {
414
+ "application/json": {
415
+ "example": {"detail": "命名空间 'production' 不存在"}
416
+ }
417
+ }
418
+ },
419
+ 500: {
420
+ "description": "服务器内部错误"
421
+ }
422
+ }
423
+ )
424
+ async def get_namespace_statistics(
425
+ namespace_name: str = Path(..., description="命名空间名称", example="default")
426
+ ) -> Dict[str, Any]:
119
427
  """
120
- 获取命名空间统计信息
121
-
122
- Args:
123
- namespace_name: 命名空间名称
428
+ ## 获取命名空间统计信息
429
+
430
+ 获取指定命名空间的实时统计数据,用于监控和分析。
431
+
432
+ **统计指标包括**:
433
+ - 队列总数
434
+ - 任务总数
435
+ - 活跃 Worker 数
436
+ - Redis 内存使用情况
437
+ - 数据库连接数
438
+
439
+ **使用场景**:
440
+ - 命名空间监控面板
441
+ - 资源使用分析
442
+ - 容量规划
443
+ - 性能优化
444
+
445
+ **示例请求**:
446
+ ```bash
447
+ curl -X GET "http://localhost:8001/api/v1/namespaces/default/statistics"
448
+ ```
449
+
450
+ **返回示例**:
451
+ ```json
452
+ {
453
+ "success": true,
454
+ "data": {
455
+ "total_queues": 5,
456
+ "total_tasks": 1250,
457
+ "active_workers": 12,
458
+ "redis_memory_usage": 10485760,
459
+ "db_connections": 5
460
+ },
461
+ "namespace": "default"
462
+ }
463
+ ```
464
+
465
+ **注意事项**:
466
+ - 统计数据为实时查询,可能会有轻微延迟
467
+ - Redis 内存使用单位为字节(bytes)
468
+ - 如果命名空间未启用,某些统计数据可能为 0
124
469
  """
125
470
  try:
126
471
  return await SettingsService.get_namespace_statistics(namespace_name)