jettask 0.2.18__py3-none-any.whl → 0.2.20__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 (165) hide show
  1. jettask/__init__.py +60 -2
  2. jettask/cli.py +314 -228
  3. jettask/config/__init__.py +9 -1
  4. jettask/config/config.py +245 -0
  5. jettask/config/env_loader.py +381 -0
  6. jettask/config/lua_scripts.py +158 -0
  7. jettask/config/nacos_config.py +132 -5
  8. jettask/core/__init__.py +1 -1
  9. jettask/core/app.py +1573 -666
  10. jettask/core/app_importer.py +33 -16
  11. jettask/core/container.py +532 -0
  12. jettask/core/task.py +1 -4
  13. jettask/core/unified_manager_base.py +2 -2
  14. jettask/executor/__init__.py +38 -0
  15. jettask/executor/core.py +625 -0
  16. jettask/executor/executor.py +338 -0
  17. jettask/executor/orchestrator.py +290 -0
  18. jettask/executor/process_entry.py +638 -0
  19. jettask/executor/task_executor.py +317 -0
  20. jettask/messaging/__init__.py +68 -0
  21. jettask/messaging/event_pool.py +2188 -0
  22. jettask/messaging/reader.py +519 -0
  23. jettask/messaging/registry.py +266 -0
  24. jettask/messaging/scanner.py +369 -0
  25. jettask/messaging/sender.py +312 -0
  26. jettask/persistence/__init__.py +118 -0
  27. jettask/persistence/backlog_monitor.py +567 -0
  28. jettask/{backend/data_access.py → persistence/base.py} +58 -57
  29. jettask/persistence/consumer.py +315 -0
  30. jettask/{core → persistence}/db_manager.py +23 -22
  31. jettask/persistence/maintenance.py +81 -0
  32. jettask/persistence/message_consumer.py +259 -0
  33. jettask/{backend/namespace_data_access.py → persistence/namespace.py} +66 -98
  34. jettask/persistence/offline_recovery.py +196 -0
  35. jettask/persistence/queue_discovery.py +215 -0
  36. jettask/persistence/task_persistence.py +218 -0
  37. jettask/persistence/task_updater.py +583 -0
  38. jettask/scheduler/__init__.py +2 -2
  39. jettask/scheduler/loader.py +6 -5
  40. jettask/scheduler/run_scheduler.py +1 -1
  41. jettask/scheduler/scheduler.py +7 -7
  42. jettask/scheduler/{unified_scheduler_manager.py → scheduler_coordinator.py} +18 -13
  43. jettask/task/__init__.py +16 -0
  44. jettask/{router.py → task/router.py} +26 -8
  45. jettask/task/task_center/__init__.py +9 -0
  46. jettask/task/task_executor.py +318 -0
  47. jettask/task/task_registry.py +291 -0
  48. jettask/test_connection_monitor.py +73 -0
  49. jettask/utils/__init__.py +31 -1
  50. jettask/{monitor/run_backlog_collector.py → utils/backlog_collector.py} +1 -1
  51. jettask/utils/db_connector.py +1629 -0
  52. jettask/{db_init.py → utils/db_init.py} +1 -1
  53. jettask/utils/rate_limit/__init__.py +30 -0
  54. jettask/utils/rate_limit/concurrency_limiter.py +665 -0
  55. jettask/utils/rate_limit/config.py +145 -0
  56. jettask/utils/rate_limit/limiter.py +41 -0
  57. jettask/utils/rate_limit/manager.py +269 -0
  58. jettask/utils/rate_limit/qps_limiter.py +154 -0
  59. jettask/utils/rate_limit/task_limiter.py +384 -0
  60. jettask/utils/serializer.py +3 -0
  61. jettask/{monitor/stream_backlog_monitor.py → utils/stream_backlog.py} +14 -6
  62. jettask/utils/time_sync.py +173 -0
  63. jettask/webui/__init__.py +27 -0
  64. jettask/{api/v1 → webui/api}/alerts.py +1 -1
  65. jettask/{api/v1 → webui/api}/analytics.py +2 -2
  66. jettask/{api/v1 → webui/api}/namespaces.py +1 -1
  67. jettask/{api/v1 → webui/api}/overview.py +1 -1
  68. jettask/{api/v1 → webui/api}/queues.py +3 -3
  69. jettask/{api/v1 → webui/api}/scheduled.py +1 -1
  70. jettask/{api/v1 → webui/api}/settings.py +1 -1
  71. jettask/{api.py → webui/app.py} +253 -145
  72. jettask/webui/namespace_manager/__init__.py +10 -0
  73. jettask/{multi_namespace_consumer.py → webui/namespace_manager/multi.py} +69 -22
  74. jettask/{unified_consumer_manager.py → webui/namespace_manager/unified.py} +1 -1
  75. jettask/{run.py → webui/run.py} +2 -2
  76. jettask/{services → webui/services}/__init__.py +1 -3
  77. jettask/{services → webui/services}/overview_service.py +34 -16
  78. jettask/{services → webui/services}/queue_service.py +1 -1
  79. jettask/{backend → webui/services}/queue_stats_v2.py +1 -1
  80. jettask/{services → webui/services}/settings_service.py +1 -1
  81. jettask/worker/__init__.py +53 -0
  82. jettask/worker/lifecycle.py +1507 -0
  83. jettask/worker/manager.py +583 -0
  84. jettask/{core/offline_worker_recovery.py → worker/recovery.py} +268 -175
  85. {jettask-0.2.18.dist-info → jettask-0.2.20.dist-info}/METADATA +2 -71
  86. jettask-0.2.20.dist-info/RECORD +145 -0
  87. jettask/__main__.py +0 -140
  88. jettask/api/__init__.py +0 -103
  89. jettask/backend/__init__.py +0 -1
  90. jettask/backend/api/__init__.py +0 -3
  91. jettask/backend/api/v1/__init__.py +0 -17
  92. jettask/backend/api/v1/monitoring.py +0 -431
  93. jettask/backend/api/v1/namespaces.py +0 -504
  94. jettask/backend/api/v1/queues.py +0 -342
  95. jettask/backend/api/v1/tasks.py +0 -367
  96. jettask/backend/core/__init__.py +0 -3
  97. jettask/backend/core/cache.py +0 -221
  98. jettask/backend/core/database.py +0 -200
  99. jettask/backend/core/exceptions.py +0 -102
  100. jettask/backend/dependencies.py +0 -261
  101. jettask/backend/init_meta_db.py +0 -158
  102. jettask/backend/main.py +0 -1426
  103. jettask/backend/main_unified.py +0 -78
  104. jettask/backend/main_v2.py +0 -394
  105. jettask/backend/models/__init__.py +0 -3
  106. jettask/backend/models/requests.py +0 -236
  107. jettask/backend/models/responses.py +0 -230
  108. jettask/backend/namespace_api_old.py +0 -267
  109. jettask/backend/services/__init__.py +0 -3
  110. jettask/backend/start.py +0 -42
  111. jettask/backend/unified_api_router.py +0 -1541
  112. jettask/cleanup_deprecated_tables.sql +0 -16
  113. jettask/core/consumer_manager.py +0 -1695
  114. jettask/core/delay_scanner.py +0 -256
  115. jettask/core/event_pool.py +0 -1700
  116. jettask/core/heartbeat_process.py +0 -222
  117. jettask/core/task_batch.py +0 -153
  118. jettask/core/worker_scanner.py +0 -271
  119. jettask/executors/__init__.py +0 -5
  120. jettask/executors/asyncio.py +0 -876
  121. jettask/executors/base.py +0 -30
  122. jettask/executors/common.py +0 -148
  123. jettask/executors/multi_asyncio.py +0 -309
  124. jettask/gradio_app.py +0 -570
  125. jettask/integrated_gradio_app.py +0 -1088
  126. jettask/main.py +0 -0
  127. jettask/monitoring/__init__.py +0 -3
  128. jettask/pg_consumer.py +0 -1896
  129. jettask/run_monitor.py +0 -22
  130. jettask/run_webui.py +0 -148
  131. jettask/scheduler/multi_namespace_scheduler.py +0 -294
  132. jettask/scheduler/unified_manager.py +0 -450
  133. jettask/task_center_client.py +0 -150
  134. jettask/utils/serializer_optimized.py +0 -33
  135. jettask/webui_exceptions.py +0 -67
  136. jettask-0.2.18.dist-info/RECORD +0 -150
  137. /jettask/{constants.py → config/constants.py} +0 -0
  138. /jettask/{backend/config.py → config/task_center.py} +0 -0
  139. /jettask/{pg_consumer → messaging/pg_consumer}/pg_consumer_v2.py +0 -0
  140. /jettask/{pg_consumer → messaging/pg_consumer}/sql/add_execution_time_field.sql +0 -0
  141. /jettask/{pg_consumer → messaging/pg_consumer}/sql/create_new_tables.sql +0 -0
  142. /jettask/{pg_consumer → messaging/pg_consumer}/sql/create_tables_v3.sql +0 -0
  143. /jettask/{pg_consumer → messaging/pg_consumer}/sql/migrate_to_new_structure.sql +0 -0
  144. /jettask/{pg_consumer → messaging/pg_consumer}/sql/modify_time_fields.sql +0 -0
  145. /jettask/{pg_consumer → messaging/pg_consumer}/sql_utils.py +0 -0
  146. /jettask/{models.py → persistence/models.py} +0 -0
  147. /jettask/scheduler/{manager.py → task_crud.py} +0 -0
  148. /jettask/{schema.sql → schemas/schema.sql} +0 -0
  149. /jettask/{task_center.py → task/task_center/client.py} +0 -0
  150. /jettask/{monitoring → utils}/file_watcher.py +0 -0
  151. /jettask/{services/redis_monitor_service.py → utils/redis_monitor.py} +0 -0
  152. /jettask/{api/v1 → webui/api}/__init__.py +0 -0
  153. /jettask/{webui_config.py → webui/config.py} +0 -0
  154. /jettask/{webui_models → webui/models}/__init__.py +0 -0
  155. /jettask/{webui_models → webui/models}/namespace.py +0 -0
  156. /jettask/{services → webui/services}/alert_service.py +0 -0
  157. /jettask/{services → webui/services}/analytics_service.py +0 -0
  158. /jettask/{services → webui/services}/scheduled_task_service.py +0 -0
  159. /jettask/{services → webui/services}/task_service.py +0 -0
  160. /jettask/{webui_sql → webui/sql}/batch_upsert_functions.sql +0 -0
  161. /jettask/{webui_sql → webui/sql}/verify_database.sql +0 -0
  162. {jettask-0.2.18.dist-info → jettask-0.2.20.dist-info}/WHEEL +0 -0
  163. {jettask-0.2.18.dist-info → jettask-0.2.20.dist-info}/entry_points.txt +0 -0
  164. {jettask-0.2.18.dist-info → jettask-0.2.20.dist-info}/licenses/LICENSE +0 -0
  165. {jettask-0.2.18.dist-info → jettask-0.2.20.dist-info}/top_level.txt +0 -0
@@ -1,256 +0,0 @@
1
- #!/usr/bin/env python
2
- """
3
- 独立的延迟队列扫描器进程
4
- 用于扫描延迟任务并投递到执行队列
5
- """
6
-
7
- import asyncio
8
- import time
9
- import logging
10
- import signal
11
- import sys
12
- from typing import Optional
13
- import uuid
14
-
15
- import redis.asyncio as aioredis
16
- from redis.asyncio.lock import Lock
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
-
21
- class DelayQueueScanner:
22
- """
23
- 独立的延迟队列扫描器
24
- 使用分布式锁确保只有一个扫描器实例在运行
25
- """
26
-
27
- def __init__(
28
- self,
29
- redis_url: str = "redis://localhost:6379/0",
30
- redis_prefix: str = "jettask",
31
- scan_interval: float = 1.0,
32
- batch_size: int = 100,
33
- lock_ttl: int = 10
34
- ):
35
- """
36
- 初始化扫描器
37
-
38
- Args:
39
- redis_url: Redis连接URL
40
- redis_prefix: Redis键前缀
41
- scan_interval: 扫描间隔(秒)
42
- batch_size: 每次处理的任务数
43
- lock_ttl: 分布式锁TTL(秒)
44
- """
45
- self.redis_url = redis_url
46
- self.redis_prefix = redis_prefix
47
- self.scan_interval = scan_interval
48
- self.batch_size = batch_size
49
- self.lock_ttl = lock_ttl
50
-
51
- self.redis: Optional[aioredis.Redis] = None
52
- self.running = False
53
- self.scanner_id = f"scanner-{uuid.uuid4().hex[:8]}"
54
-
55
- # 设置信号处理
56
- signal.signal(signal.SIGINT, self._signal_handler)
57
- signal.signal(signal.SIGTERM, self._signal_handler)
58
-
59
- def _signal_handler(self, signum, frame):
60
- """信号处理器"""
61
- logger.info(f"Received signal {signum}, stopping scanner...")
62
- self.running = False
63
-
64
- async def connect(self):
65
- """建立Redis连接"""
66
- if not self.redis:
67
- self.redis = await aioredis.from_url(
68
- self.redis_url,
69
- encoding="utf-8",
70
- decode_responses=False
71
- )
72
- logger.info(f"Scanner {self.scanner_id} connected to Redis")
73
-
74
- async def disconnect(self):
75
- """关闭Redis连接"""
76
- if self.redis:
77
- await self.redis.close()
78
- self.redis = None
79
-
80
- def _get_queue_key(self) -> str:
81
- """获取延迟队列键名"""
82
- return f"{self.redis_prefix}:DELAYED:QUEUE"
83
-
84
- def _get_task_key(self, task_id: str) -> str:
85
- """获取任务详情键名"""
86
- return f"{self.redis_prefix}:DELAYED:TASK:{task_id}"
87
-
88
- def _get_lock_key(self) -> str:
89
- """获取分布式锁键名"""
90
- return f"{self.redis_prefix}:DELAYED:SCANNER_LOCK"
91
-
92
- def get_lock(self) -> Lock:
93
- """
94
- 获取Redis分布式锁对象
95
-
96
- Returns:
97
- Redis Lock对象
98
- """
99
- return Lock(
100
- self.redis,
101
- self._get_lock_key(),
102
- timeout=self.lock_ttl, # 锁的自动过期时间
103
- blocking=True, # 阻塞获取
104
- blocking_timeout=0.1 # 最多等待0.1秒
105
- )
106
-
107
- async def scan_and_deliver(self) -> int:
108
- """
109
- 扫描并投递到期任务
110
-
111
- Returns:
112
- 处理的任务数
113
- """
114
- # 使用Redis原生锁
115
- lock = self.get_lock()
116
-
117
- # 尝试获取锁
118
- async with lock:
119
- now = time.time()
120
- processed_count = 0
121
-
122
- # 使用ZPOPMIN原子地获取并移除到期任务
123
- for _ in range(self.batch_size):
124
- # 获取分数最小的任务
125
- result = await self.redis.zpopmin(self._get_queue_key(), 1)
126
-
127
- if not result:
128
- break
129
-
130
- for item in result:
131
- if len(item) == 2:
132
- task_id_bytes, score = item
133
- task_id = task_id_bytes.decode() if isinstance(task_id_bytes, bytes) else task_id_bytes
134
-
135
- # 检查是否到期
136
- if score > now:
137
- # 还没到期,放回队列
138
- await self.redis.zadd(self._get_queue_key(), {task_id: score})
139
- break # 后面的任务肯定也没到期
140
-
141
- # 处理到期任务
142
- try:
143
- await self.deliver_task(task_id)
144
- processed_count += 1
145
- except Exception as e:
146
- logger.error(f"Failed to deliver task {task_id}: {e}")
147
- # 失败的任务延迟10秒重试
148
- retry_time = time.time() + 10
149
- await self.redis.zadd(self._get_queue_key(), {task_id: retry_time})
150
-
151
- if processed_count > 0:
152
- logger.info(f"Scanner {self.scanner_id} delivered {processed_count} tasks")
153
-
154
- return processed_count
155
-
156
- async def deliver_task(self, task_id: str):
157
- """
158
- 投递任务到执行队列
159
-
160
- Args:
161
- task_id: 任务ID
162
- """
163
- # 获取任务详情
164
- task_json = await self.redis.get(self._get_task_key(task_id))
165
-
166
- if not task_json:
167
- logger.warning(f"Task {task_id} not found, skipping")
168
- return
169
-
170
- import json
171
- task_info = json.loads(task_json)
172
-
173
- queue_name = task_info['queue_name']
174
- task_data = task_info['task_data']
175
-
176
- # 写入到执行队列(Redis Stream)
177
- stream_key = f"{self.redis_prefix}:{queue_name}"
178
- await self.redis.xadd(stream_key, {'data': json.dumps(task_data)})
179
-
180
- # 更新任务状态
181
- event_id = task_data.get('event_id', task_id)
182
- status_key = f"{self.redis_prefix}:TASK:{event_id}"
183
- await self.redis.hset(status_key, "status", "pending")
184
-
185
- # 删除任务详情
186
- await self.redis.delete(self._get_task_key(task_id))
187
-
188
- logger.info(f"Delivered task {task_id} to queue {queue_name}")
189
-
190
- async def run(self):
191
- """运行扫描器"""
192
- await self.connect()
193
-
194
- self.running = True
195
- logger.info(f"Delay queue scanner {self.scanner_id} started")
196
- logger.info(f"Scan interval: {self.scan_interval}s, Batch size: {self.batch_size}")
197
-
198
- try:
199
- while self.running:
200
- try:
201
- # 扫描并投递任务
202
- await self.scan_and_deliver()
203
- except Exception as e:
204
- logger.error(f"Scanner error: {e}", exc_info=True)
205
-
206
- # 等待下一次扫描
207
- await asyncio.sleep(self.scan_interval)
208
-
209
- finally:
210
- logger.info(f"Scanner {self.scanner_id} stopped")
211
- await self.disconnect()
212
-
213
-
214
- async def main():
215
- """主函数"""
216
- import argparse
217
-
218
- # 配置日志
219
- logging.basicConfig(
220
- level=logging.INFO,
221
- format='%(asctime)s - %(levelname)s - %(message)s',
222
- datefmt='%Y-%m-%d %H:%M:%S'
223
- )
224
-
225
- # 解析命令行参数
226
- parser = argparse.ArgumentParser(description='Jettask Delay Queue Scanner')
227
- parser.add_argument('--redis-url', default='redis://localhost:6379/0',
228
- help='Redis connection URL')
229
- parser.add_argument('--redis-prefix', default='jettask',
230
- help='Redis key prefix')
231
- parser.add_argument('--scan-interval', type=float, default=1.0,
232
- help='Scan interval in seconds')
233
- parser.add_argument('--batch-size', type=int, default=100,
234
- help='Number of tasks to process per scan')
235
- parser.add_argument('--lock-ttl', type=int, default=10,
236
- help='Distributed lock TTL in seconds')
237
-
238
- args = parser.parse_args()
239
-
240
- # 创建并运行扫描器
241
- scanner = DelayQueueScanner(
242
- redis_url=args.redis_url,
243
- redis_prefix=args.redis_prefix,
244
- scan_interval=args.scan_interval,
245
- batch_size=args.batch_size,
246
- lock_ttl=args.lock_ttl
247
- )
248
-
249
- try:
250
- await scanner.run()
251
- except KeyboardInterrupt:
252
- logger.info("Scanner interrupted by user")
253
-
254
-
255
- if __name__ == '__main__':
256
- asyncio.run(main())