jettask 0.2.4__py3-none-any.whl → 0.2.6__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.
- jettask/core/cli.py +20 -24
- jettask/monitor/run_backlog_collector.py +96 -0
- jettask/monitor/stream_backlog_monitor.py +362 -0
- jettask/pg_consumer/pg_consumer_v2.py +403 -0
- jettask/pg_consumer/sql_utils.py +182 -0
- jettask/scheduler/__init__.py +17 -0
- jettask/scheduler/add_execution_count.sql +11 -0
- jettask/scheduler/add_priority_field.sql +26 -0
- jettask/scheduler/add_scheduler_id.sql +25 -0
- jettask/scheduler/add_scheduler_id_index.sql +10 -0
- jettask/scheduler/loader.py +249 -0
- jettask/scheduler/make_scheduler_id_required.sql +28 -0
- jettask/scheduler/manager.py +696 -0
- jettask/scheduler/migrate_interval_seconds.sql +9 -0
- jettask/scheduler/models.py +200 -0
- jettask/scheduler/multi_namespace_scheduler.py +294 -0
- jettask/scheduler/performance_optimization.sql +45 -0
- jettask/scheduler/run_scheduler.py +186 -0
- jettask/scheduler/scheduler.py +715 -0
- jettask/scheduler/schema.sql +84 -0
- jettask/scheduler/unified_manager.py +450 -0
- jettask/scheduler/unified_scheduler_manager.py +280 -0
- jettask/webui/backend/api/__init__.py +3 -0
- jettask/webui/backend/api/v1/__init__.py +17 -0
- jettask/webui/backend/api/v1/monitoring.py +431 -0
- jettask/webui/backend/api/v1/namespaces.py +504 -0
- jettask/webui/backend/api/v1/queues.py +342 -0
- jettask/webui/backend/api/v1/tasks.py +367 -0
- jettask/webui/backend/core/__init__.py +3 -0
- jettask/webui/backend/core/cache.py +221 -0
- jettask/webui/backend/core/database.py +200 -0
- jettask/webui/backend/core/exceptions.py +102 -0
- jettask/webui/backend/models/__init__.py +3 -0
- jettask/webui/backend/models/requests.py +236 -0
- jettask/webui/backend/models/responses.py +230 -0
- jettask/webui/backend/services/__init__.py +3 -0
- jettask/webui/frontend/index.html +13 -0
- jettask/webui/models/__init__.py +3 -0
- jettask/webui/models/namespace.py +63 -0
- jettask/webui/sql/batch_upsert_functions.sql +178 -0
- jettask/webui/sql/init_database.sql +640 -0
- {jettask-0.2.4.dist-info → jettask-0.2.6.dist-info}/METADATA +11 -9
- {jettask-0.2.4.dist-info → jettask-0.2.6.dist-info}/RECORD +47 -54
- jettask/webui/frontend/package-lock.json +0 -4833
- jettask/webui/frontend/package.json +0 -30
- jettask/webui/frontend/src/App.css +0 -109
- jettask/webui/frontend/src/App.jsx +0 -66
- jettask/webui/frontend/src/components/NamespaceSelector.jsx +0 -166
- jettask/webui/frontend/src/components/QueueBacklogChart.jsx +0 -298
- jettask/webui/frontend/src/components/QueueBacklogTrend.jsx +0 -638
- jettask/webui/frontend/src/components/QueueDetailsTable.css +0 -65
- jettask/webui/frontend/src/components/QueueDetailsTable.jsx +0 -487
- jettask/webui/frontend/src/components/QueueDetailsTableV2.jsx +0 -465
- jettask/webui/frontend/src/components/ScheduledTaskFilter.jsx +0 -423
- jettask/webui/frontend/src/components/TaskFilter.jsx +0 -425
- jettask/webui/frontend/src/components/TimeRangeSelector.css +0 -21
- jettask/webui/frontend/src/components/TimeRangeSelector.jsx +0 -160
- jettask/webui/frontend/src/components/charts/QueueChart.jsx +0 -111
- jettask/webui/frontend/src/components/charts/QueueTrendChart.jsx +0 -115
- jettask/webui/frontend/src/components/charts/WorkerChart.jsx +0 -40
- jettask/webui/frontend/src/components/common/StatsCard.jsx +0 -18
- jettask/webui/frontend/src/components/layout/AppLayout.css +0 -95
- jettask/webui/frontend/src/components/layout/AppLayout.jsx +0 -49
- jettask/webui/frontend/src/components/layout/Header.css +0 -106
- jettask/webui/frontend/src/components/layout/Header.jsx +0 -106
- jettask/webui/frontend/src/components/layout/SideMenu.css +0 -137
- jettask/webui/frontend/src/components/layout/SideMenu.jsx +0 -209
- jettask/webui/frontend/src/components/layout/TabsNav.css +0 -244
- jettask/webui/frontend/src/components/layout/TabsNav.jsx +0 -206
- jettask/webui/frontend/src/components/layout/UserInfo.css +0 -197
- jettask/webui/frontend/src/components/layout/UserInfo.jsx +0 -197
- jettask/webui/frontend/src/contexts/LoadingContext.jsx +0 -27
- jettask/webui/frontend/src/contexts/NamespaceContext.jsx +0 -72
- jettask/webui/frontend/src/contexts/TabsContext.backup.jsx +0 -245
- jettask/webui/frontend/src/index.css +0 -114
- jettask/webui/frontend/src/main.jsx +0 -20
- jettask/webui/frontend/src/pages/Alerts.jsx +0 -684
- jettask/webui/frontend/src/pages/Dashboard/index.css +0 -35
- jettask/webui/frontend/src/pages/Dashboard/index.jsx +0 -281
- jettask/webui/frontend/src/pages/Dashboard.jsx +0 -1330
- jettask/webui/frontend/src/pages/QueueDetail.jsx +0 -1117
- jettask/webui/frontend/src/pages/QueueMonitor.jsx +0 -527
- jettask/webui/frontend/src/pages/Queues.jsx +0 -12
- jettask/webui/frontend/src/pages/ScheduledTasks.jsx +0 -809
- jettask/webui/frontend/src/pages/Settings.jsx +0 -800
- jettask/webui/frontend/src/pages/Workers.jsx +0 -12
- jettask/webui/frontend/src/services/api.js +0 -114
- jettask/webui/frontend/src/services/queueTrend.js +0 -152
- jettask/webui/frontend/src/utils/suppressWarnings.js +0 -22
- jettask/webui/frontend/src/utils/userPreferences.js +0 -154
- {jettask-0.2.4.dist-info → jettask-0.2.6.dist-info}/WHEEL +0 -0
- {jettask-0.2.4.dist-info → jettask-0.2.6.dist-info}/entry_points.txt +0 -0
- {jettask-0.2.4.dist-info → jettask-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {jettask-0.2.4.dist-info → jettask-0.2.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
"""
|
3
|
+
定时任务调度器启动脚本
|
4
|
+
"""
|
5
|
+
import asyncio
|
6
|
+
import os
|
7
|
+
import sys
|
8
|
+
import signal
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
# 添加项目根目录到Python路径
|
12
|
+
project_root = Path(__file__).parent.parent.parent
|
13
|
+
sys.path.insert(0, str(project_root))
|
14
|
+
|
15
|
+
from jettask import Jettask
|
16
|
+
from jettask.scheduler.scheduler import TaskScheduler
|
17
|
+
from jettask.scheduler.manager import ScheduledTaskManager
|
18
|
+
from jettask.utils.task_logger import get_task_logger
|
19
|
+
|
20
|
+
logger = get_task_logger(__name__)
|
21
|
+
|
22
|
+
|
23
|
+
class SchedulerRunner:
|
24
|
+
"""调度器运行器"""
|
25
|
+
|
26
|
+
def __init__(self):
|
27
|
+
self.scheduler = None
|
28
|
+
self.app = None
|
29
|
+
self.running = False
|
30
|
+
|
31
|
+
async def setup(self):
|
32
|
+
"""初始化设置"""
|
33
|
+
# 从环境变量获取配置
|
34
|
+
redis_url = os.getenv('JETTASK_REDIS_URL', 'redis://localhost:6379/0')
|
35
|
+
db_url = os.getenv('JETTASK_PG_URL', 'postgresql://jettask:123456@localhost:5432/jettask')
|
36
|
+
|
37
|
+
# 创建Jettask应用实例
|
38
|
+
self.app = Jettask(
|
39
|
+
redis_url=redis_url,
|
40
|
+
pg_url=db_url
|
41
|
+
)
|
42
|
+
|
43
|
+
# 导入任务模块(确保任务被注册)
|
44
|
+
try:
|
45
|
+
# 尝试导入用户定义的任务模块
|
46
|
+
import importlib
|
47
|
+
import importlib.util
|
48
|
+
|
49
|
+
# 先尝试加载示例模块
|
50
|
+
example_paths = [
|
51
|
+
'examples.scheduler_auto_demo',
|
52
|
+
'scheduler_auto_demo'
|
53
|
+
]
|
54
|
+
|
55
|
+
for path in example_paths:
|
56
|
+
try:
|
57
|
+
example_module = importlib.import_module(path)
|
58
|
+
if hasattr(example_module, 'app'):
|
59
|
+
# 将任务模块中的任务复制到调度器的app中
|
60
|
+
for task_name, task_obj in example_module.app._tasks.items():
|
61
|
+
self.app._tasks[task_name] = task_obj
|
62
|
+
# 也注册带模块名的任务
|
63
|
+
full_name = f"scheduler_auto_demo.{task_name}"
|
64
|
+
self.app._tasks[full_name] = task_obj
|
65
|
+
logger.info(f"Registered task: {task_name} and {full_name}")
|
66
|
+
logger.info(f"Loaded example tasks from module: {path}")
|
67
|
+
break
|
68
|
+
except ImportError:
|
69
|
+
continue
|
70
|
+
|
71
|
+
# 然后加载用户指定的任务模块
|
72
|
+
task_module = os.getenv('JETTASK_TASKS_MODULE', 'tasks')
|
73
|
+
if task_module:
|
74
|
+
try:
|
75
|
+
module = importlib.import_module(task_module)
|
76
|
+
# 获取模块中的app对象的任务
|
77
|
+
if hasattr(module, 'app'):
|
78
|
+
# 将任务模块中的任务复制到调度器的app中
|
79
|
+
for task_name, task_obj in module.app._tasks.items():
|
80
|
+
self.app._tasks[task_name] = task_obj
|
81
|
+
logger.info(f"Registered task: {task_name}")
|
82
|
+
|
83
|
+
# 注册别名任务(scheduler_auto_demo.send_notification)
|
84
|
+
if hasattr(module, 'send_notification'):
|
85
|
+
self.app._tasks['scheduler_auto_demo.send_notification'] = module.send_notification
|
86
|
+
logger.info("Registered task: scheduler_auto_demo.send_notification")
|
87
|
+
|
88
|
+
logger.info(f"Loaded tasks from module: {task_module}")
|
89
|
+
except ImportError as e:
|
90
|
+
logger.warning(f"Could not import tasks module '{task_module}': {e}")
|
91
|
+
except Exception as e:
|
92
|
+
logger.warning(f"Error loading tasks: {e}")
|
93
|
+
|
94
|
+
# 创建数据库管理器
|
95
|
+
db_manager = ScheduledTaskManager(db_url)
|
96
|
+
await db_manager.connect()
|
97
|
+
|
98
|
+
# 确保数据库表存在
|
99
|
+
await db_manager.init_schema()
|
100
|
+
|
101
|
+
# 创建调度器
|
102
|
+
self.scheduler = TaskScheduler(
|
103
|
+
app=self.app,
|
104
|
+
redis_url=redis_url,
|
105
|
+
db_manager=db_manager,
|
106
|
+
redis_prefix="jettask:scheduled",
|
107
|
+
scan_interval=0.5, # 每0.5秒扫描一次
|
108
|
+
batch_size=100, # 每批处理100个任务
|
109
|
+
leader_ttl=30 # Leader锁30秒过期
|
110
|
+
)
|
111
|
+
|
112
|
+
await self.scheduler.connect()
|
113
|
+
logger.info("Scheduler setup completed")
|
114
|
+
|
115
|
+
async def run(self):
|
116
|
+
"""运行调度器"""
|
117
|
+
self.running = True
|
118
|
+
logger.info("Starting scheduler...")
|
119
|
+
|
120
|
+
try:
|
121
|
+
# 运行调度器
|
122
|
+
await self.scheduler.run()
|
123
|
+
except Exception as e:
|
124
|
+
logger.error(f"Scheduler error: {e}", exc_info=True)
|
125
|
+
finally:
|
126
|
+
self.running = False
|
127
|
+
logger.info("Scheduler stopped")
|
128
|
+
|
129
|
+
async def shutdown(self):
|
130
|
+
"""关闭调度器"""
|
131
|
+
logger.info("Shutting down scheduler...")
|
132
|
+
|
133
|
+
if self.scheduler:
|
134
|
+
self.scheduler.stop()
|
135
|
+
await self.scheduler.disconnect()
|
136
|
+
|
137
|
+
if self.app:
|
138
|
+
# 关闭应用连接
|
139
|
+
pass
|
140
|
+
|
141
|
+
logger.info("Scheduler shutdown completed")
|
142
|
+
|
143
|
+
def handle_signal(self, signum, frame):
|
144
|
+
"""处理终止信号"""
|
145
|
+
logger.info(f"Received signal {signum}, initiating shutdown...")
|
146
|
+
self.running = False
|
147
|
+
|
148
|
+
# 创建关闭任务
|
149
|
+
if self.scheduler:
|
150
|
+
self.scheduler.stop()
|
151
|
+
|
152
|
+
|
153
|
+
async def main():
|
154
|
+
"""主函数"""
|
155
|
+
runner = SchedulerRunner()
|
156
|
+
|
157
|
+
# 设置信号处理
|
158
|
+
signal.signal(signal.SIGINT, runner.handle_signal)
|
159
|
+
signal.signal(signal.SIGTERM, runner.handle_signal)
|
160
|
+
|
161
|
+
try:
|
162
|
+
# 初始化
|
163
|
+
await runner.setup()
|
164
|
+
|
165
|
+
# 运行调度器
|
166
|
+
await runner.run()
|
167
|
+
|
168
|
+
except KeyboardInterrupt:
|
169
|
+
logger.info("Received keyboard interrupt")
|
170
|
+
except Exception as e:
|
171
|
+
logger.error(f"Unexpected error: {e}", exc_info=True)
|
172
|
+
finally:
|
173
|
+
# 清理
|
174
|
+
await runner.shutdown()
|
175
|
+
|
176
|
+
|
177
|
+
if __name__ == '__main__':
|
178
|
+
# 设置日志级别
|
179
|
+
import logging
|
180
|
+
logging.basicConfig(
|
181
|
+
level=logging.INFO,
|
182
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
183
|
+
)
|
184
|
+
|
185
|
+
# 运行主函数
|
186
|
+
asyncio.run(main())
|