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
jettask/run_monitor.py DELETED
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env python
2
- """启动任务监控服务"""
3
-
4
- import uvicorn
5
- import sys
6
- import os
7
-
8
- # 添加当前目录到Python路径
9
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
10
-
11
- if __name__ == "__main__":
12
- print("Starting JetTask Monitor Backend...")
13
- print("API will be available at: http://localhost:8000")
14
- print("API docs: http://localhost:8000/docs")
15
-
16
- uvicorn.run(
17
- "backend.main:app",
18
- host="0.0.0.0",
19
- port=8000,
20
- reload=True,
21
- reload_dirs=[os.path.dirname(os.path.abspath(__file__))]
22
- )
jettask/run_webui.py DELETED
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- JetTask WebUI 启动脚本
4
- 支持多种界面模式:
5
- 1. FastAPI + HTML (原始模式)
6
- 2. Gradio 界面 (新模式)
7
- """
8
-
9
- import argparse
10
- import asyncio
11
- import logging
12
- import os
13
- import sys
14
- from pathlib import Path
15
-
16
- # 添加项目根目录到Python路径
17
- project_root = Path(__file__).parent.parent.parent
18
- sys.path.insert(0, str(project_root))
19
-
20
- from jettask.webui_config import PostgreSQLConfig
21
-
22
-
23
- def run_fastapi_server(host: str = "0.0.0.0", port: int = 8000, with_consumer: bool = False):
24
- """运行FastAPI服务器"""
25
- import uvicorn
26
- from jettask.api import app
27
-
28
- # 如果需要启动消费者
29
- if with_consumer:
30
- pg_config = PostgreSQLConfig.from_env()
31
- if pg_config.dsn:
32
- app.state.pg_config = pg_config
33
- app.state.enable_consumer = True
34
- print("PostgreSQL consumer will be started with the server")
35
- else:
36
- print("Warning: PostgreSQL configuration not found, consumer disabled")
37
-
38
- print(f"Starting FastAPI server on http://{host}:{port}")
39
- print("Access the web interface at http://localhost:8000/")
40
-
41
- uvicorn.run(
42
- "jettask.webui.api:app",
43
- host=host,
44
- port=port,
45
- reload=False,
46
- log_level="info"
47
- )
48
-
49
-
50
- def run_gradio_interface(host: str = "0.0.0.0", port: int = 7860, share: bool = False):
51
- """运行Gradio界面"""
52
- # 确保FastAPI服务器正在运行
53
- print("Note: Make sure the FastAPI server is running on port 8000")
54
- print("You can start it with: python -m jettask.webui.run_webui --mode fastapi")
55
- print()
56
-
57
- from jettask.gradio_app import create_interface
58
-
59
- app = create_interface()
60
- print(f"Starting Gradio interface on http://{host}:{port}")
61
-
62
- app.launch(
63
- server_name=host,
64
- server_port=port,
65
- share=share,
66
- inbrowser=True
67
- )
68
-
69
-
70
- def run_combined_mode(host: str = "0.0.0.0", api_port: int = 8000, ui_port: int = 7860):
71
- """同时运行FastAPI和Gradio"""
72
- import subprocess
73
- import time
74
-
75
- # 启动FastAPI服务器
76
- print("Starting FastAPI server...")
77
- api_process = subprocess.Popen([
78
- sys.executable, "-m", "jettask.webui.api"
79
- ])
80
-
81
- # 等待API服务器启动
82
- time.sleep(3)
83
-
84
- # 启动Gradio界面
85
- print("\nStarting Gradio interface...")
86
- try:
87
- run_gradio_interface(host, ui_port, share=False)
88
- except KeyboardInterrupt:
89
- print("\nShutting down...")
90
- finally:
91
- api_process.terminate()
92
- api_process.wait()
93
-
94
-
95
- def run_integrated_gradio(host: str = "0.0.0.0", port: int = 7860, share: bool = False):
96
- """运行集成的Gradio界面(直接访问数据源)"""
97
- from jettask.integrated_gradio_app import create_integrated_interface
98
-
99
- print("Starting Integrated Gradio interface (direct data access)...")
100
- print(f"Access the interface at http://{host}:{port}")
101
-
102
- app = create_integrated_interface()
103
- app.launch(
104
- server_name=host,
105
- server_port=port,
106
- share=share,
107
- inbrowser=True
108
- )
109
-
110
-
111
- def main():
112
- parser = argparse.ArgumentParser(description="JetTask WebUI 启动器")
113
- parser.add_argument(
114
- "--mode",
115
- choices=["fastapi", "gradio", "combined", "integrated"],
116
- default="integrated",
117
- help="界面模式: fastapi(原始HTML), gradio(新界面), combined(同时启动), integrated(集成版,直接访问数据)"
118
- )
119
- parser.add_argument("--host", default="0.0.0.0", help="服务器地址")
120
- parser.add_argument("--port", type=int, help="服务器端口")
121
- parser.add_argument("--with-consumer", action="store_true", help="启动PostgreSQL消费者")
122
- parser.add_argument("--share", action="store_true", help="创建Gradio公共链接")
123
-
124
- args = parser.parse_args()
125
-
126
- # 设置日志
127
- logging.basicConfig(
128
- level=logging.INFO,
129
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
130
- )
131
-
132
- if args.mode == "fastapi":
133
- port = args.port or 8000
134
- run_fastapi_server(args.host, port, args.with_consumer)
135
- elif args.mode == "gradio":
136
- port = args.port or 7860
137
- run_gradio_interface(args.host, port, args.share)
138
- elif args.mode == "combined":
139
- run_combined_mode(args.host)
140
- elif args.mode == "integrated":
141
- port = args.port or 7860
142
- run_integrated_gradio(args.host, port, args.share)
143
- else:
144
- parser.print_help()
145
-
146
-
147
- if __name__ == "__main__":
148
- main()
@@ -1,294 +0,0 @@
1
- """
2
- 多命名空间调度器管理器
3
- 自动检测和管理多个命名空间的调度器实例
4
- """
5
- import asyncio
6
- import logging
7
- import multiprocessing
8
- import traceback
9
- from typing import Dict, Set
10
-
11
- from jettask import Jettask
12
- from jettask.task_center import TaskCenter
13
- from jettask.scheduler.scheduler import TaskScheduler
14
- from jettask.scheduler.manager import ScheduledTaskManager
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- class MultiNamespaceSchedulerManager:
20
- """多命名空间调度器管理器"""
21
-
22
- def __init__(self,
23
- task_center_base_url: str,
24
- check_interval: int = 30,
25
- scheduler_interval: float = 0.1,
26
- batch_size: int = 100,
27
- debug: bool = False):
28
- """
29
- 初始化多命名空间调度器管理器
30
-
31
- Args:
32
- task_center_base_url: 任务中心基础URL (如 http://localhost:8001)
33
- check_interval: 命名空间检测间隔(秒)
34
- scheduler_interval: 调度器扫描间隔(秒)
35
- batch_size: 每批处理的最大任务数
36
- debug: 是否启用调试模式
37
- """
38
- self.task_center_base_url = task_center_base_url.rstrip('/')
39
- self.check_interval = check_interval
40
- self.scheduler_interval = scheduler_interval
41
- self.batch_size = batch_size
42
- self.debug = debug
43
-
44
- # 存储每个命名空间的进程
45
- self.scheduler_processes: Dict[str, multiprocessing.Process] = {}
46
- self.running = False
47
-
48
- # 设置日志级别
49
- if debug:
50
- logging.basicConfig(level=logging.DEBUG)
51
- else:
52
- logging.basicConfig(level=logging.INFO)
53
-
54
- async def get_active_namespaces(self) -> Set[str]:
55
- """获取所有活跃的命名空间"""
56
- import aiohttp
57
-
58
- try:
59
- # 直接调用API获取命名空间列表
60
- url = f"{self.task_center_base_url}/api/namespaces"
61
-
62
- async with aiohttp.ClientSession() as session:
63
- async with session.get(url) as response:
64
- if response.status == 200:
65
- namespaces = await response.json()
66
- if namespaces:
67
- active_names = {ns['name'] for ns in namespaces if ns.get('name')}
68
- logger.info(f"发现 {len(active_names)} 个活跃的命名空间: {active_names}")
69
- return active_names
70
- else:
71
- logger.warning("没有找到任何命名空间")
72
- return set()
73
- else:
74
- logger.error(f"获取命名空间列表失败,状态码: {response.status}")
75
- return set()
76
-
77
- except Exception as e:
78
- logger.error(f"获取命名空间列表失败: {e}")
79
- return set()
80
-
81
- def start_scheduler_for_namespace(self, namespace: str):
82
- """为指定命名空间启动调度器进程"""
83
- if namespace in self.scheduler_processes:
84
- # 检查进程是否还在运行
85
- if self.scheduler_processes[namespace].is_alive():
86
- return
87
- else:
88
- # 清理已停止的进程
89
- logger.info(f"清理已停止的调度器进程: {namespace}")
90
- self.scheduler_processes[namespace].terminate()
91
- self.scheduler_processes[namespace].join(timeout=5)
92
- del self.scheduler_processes[namespace]
93
-
94
- # 创建新进程
95
- process = multiprocessing.Process(
96
- target=run_scheduler_for_namespace,
97
- args=(
98
- namespace,
99
- self.task_center_base_url,
100
- self.scheduler_interval,
101
- self.batch_size,
102
- self.debug
103
- ),
104
- name=f"scheduler_{namespace}"
105
- )
106
-
107
- process.start()
108
- self.scheduler_processes[namespace] = process
109
- logger.info(f"启动命名空间 {namespace} 的调度器进程, PID: {process.pid}")
110
-
111
- def stop_scheduler_for_namespace(self, namespace: str):
112
- """停止指定命名空间的调度器进程"""
113
- if namespace in self.scheduler_processes:
114
- process = self.scheduler_processes[namespace]
115
- if process.is_alive():
116
- logger.info(f"停止命名空间 {namespace} 的调度器进程")
117
- process.terminate()
118
- process.join(timeout=10)
119
-
120
- if process.is_alive():
121
- logger.warning(f"强制停止命名空间 {namespace} 的调度器进程")
122
- process.kill()
123
- process.join(timeout=5)
124
-
125
- del self.scheduler_processes[namespace]
126
-
127
- async def check_and_update_schedulers(self):
128
- """检查并更新调度器(添加新的,停止已删除的)"""
129
- # 获取当前活跃的命名空间
130
- active_namespaces = await self.get_active_namespaces()
131
- current_namespaces = set(self.scheduler_processes.keys())
132
-
133
- # 找出需要添加的命名空间
134
- to_add = active_namespaces - current_namespaces
135
- # 找出需要删除的命名空间
136
- to_remove = current_namespaces - active_namespaces
137
-
138
- # 启动新的调度器
139
- for namespace in to_add:
140
- logger.info(f"检测到新命名空间: {namespace}")
141
- self.start_scheduler_for_namespace(namespace)
142
-
143
- # 停止已删除的调度器
144
- for namespace in to_remove:
145
- logger.info(f"检测到命名空间已删除: {namespace}")
146
- self.stop_scheduler_for_namespace(namespace)
147
-
148
- # 检查现有进程的健康状态
149
- for namespace in active_namespaces & current_namespaces:
150
- process = self.scheduler_processes.get(namespace)
151
- if process and not process.is_alive():
152
- logger.warning(f"调度器进程 {namespace} 已停止,重新启动")
153
- del self.scheduler_processes[namespace]
154
- self.start_scheduler_for_namespace(namespace)
155
-
156
- async def run(self):
157
- """运行多命名空间调度器管理器"""
158
- self.running = True
159
- logger.info(f"启动多命名空间调度器管理器")
160
- logger.info(f"任务中心: {self.task_center_base_url}")
161
- logger.info(f"命名空间检测间隔: {self.check_interval} 秒")
162
- logger.info(f"调度器扫描间隔: {self.scheduler_interval} 秒")
163
- logger.info(f"批处理大小: {self.batch_size}")
164
-
165
- # 初始检查和启动
166
- await self.check_and_update_schedulers()
167
-
168
- # 定期检查命名空间变化
169
- while self.running:
170
- try:
171
- await asyncio.sleep(self.check_interval)
172
- await self.check_and_update_schedulers()
173
- except asyncio.CancelledError:
174
- break
175
- except Exception as e:
176
- logger.error(f"检查命名空间时出错: {e}")
177
- if self.debug:
178
- traceback.print_exc()
179
-
180
- def stop(self):
181
- """停止管理器和所有调度器"""
182
- logger.info("停止多命名空间调度器管理器")
183
- self.running = False
184
-
185
- # 停止所有调度器进程
186
- for namespace in list(self.scheduler_processes.keys()):
187
- self.stop_scheduler_for_namespace(namespace)
188
-
189
- logger.info("所有调度器已停止")
190
-
191
-
192
- def run_scheduler_for_namespace(namespace: str,
193
- task_center_base_url: str,
194
- interval: float,
195
- batch_size: int,
196
- debug: bool):
197
- """在独立进程中运行指定命名空间的调度器"""
198
- import asyncio
199
- import logging
200
- import signal
201
- import sys
202
-
203
- # 设置进程标题(如果可用)
204
- try:
205
- import setproctitle # type: ignore
206
- setproctitle.setproctitle(f"jettask-scheduler-{namespace}")
207
- except ImportError:
208
- pass
209
-
210
- # 配置日志
211
- logging.basicConfig(
212
- level=logging.DEBUG if debug else logging.INFO,
213
- format=f'%(asctime)s - %(levelname)s - [{namespace}] %(message)s'
214
- )
215
- logger = logging.getLogger(__name__)
216
-
217
- async def run_scheduler():
218
- """运行调度器的异步函数"""
219
- scheduler_instance = None
220
- try:
221
- # 构建命名空间特定的URL
222
- task_center_url = f"{task_center_base_url}/api/v1/namespaces/{namespace}"
223
- logger.info(f"连接到任务中心: {task_center_url}")
224
-
225
- # 连接任务中心
226
- tc = TaskCenter(task_center_url)
227
- if not tc._connect_sync():
228
- logger.error(f"无法连接到任务中心: {namespace}")
229
- return
230
-
231
- logger.info(f"成功连接到命名空间: {tc.namespace_name}")
232
-
233
- # 创建app实例
234
- app = Jettask(task_center=tc)
235
-
236
- if not app.redis_url or not app.pg_url:
237
- logger.error(f"任务中心配置不完整: {namespace}")
238
- return
239
-
240
- # 显示配置信息
241
- logger.info(f"命名空间 {namespace} 的调度器配置:")
242
- logger.info(f" Redis: {app.redis_url}")
243
- logger.info(f" PostgreSQL: {app.pg_url}")
244
- logger.info(f" 间隔: {interval} 秒")
245
- logger.info(f" 批大小: {batch_size}")
246
-
247
- # 创建调度器实例
248
- manager = ScheduledTaskManager(app)
249
- scheduler_instance = TaskScheduler(
250
- app=app,
251
- db_manager=manager,
252
- scan_interval=interval,
253
- batch_size=batch_size
254
- )
255
-
256
- # 运行调度器(run方法内部会处理连接)
257
- logger.info(f"启动命名空间 {namespace} 的调度器...")
258
- await scheduler_instance.run()
259
-
260
- except asyncio.CancelledError:
261
- logger.info(f"调度器 {namespace} 收到取消信号")
262
- except KeyboardInterrupt:
263
- logger.info(f"调度器 {namespace} 收到中断信号")
264
- except Exception as e:
265
- logger.error(f"调度器 {namespace} 运行错误: {e}")
266
- if debug:
267
- traceback.print_exc()
268
- finally:
269
- # 清理资源
270
- if scheduler_instance:
271
- scheduler_instance.stop()
272
-
273
- logger.info(f"调度器 {namespace} 已停止")
274
-
275
- # 设置信号处理
276
- import signal
277
- import sys
278
-
279
- def signal_handler(signum, frame):
280
- logger.info(f"调度器 {namespace} 收到信号 {signum}")
281
- sys.exit(0)
282
-
283
- signal.signal(signal.SIGTERM, signal_handler)
284
- signal.signal(signal.SIGINT, signal_handler)
285
-
286
- # 运行调度器
287
- try:
288
- asyncio.run(run_scheduler())
289
- except (KeyboardInterrupt, SystemExit):
290
- logger.info(f"调度器 {namespace} 正常退出")
291
- except Exception as e:
292
- logger.error(f"调度器 {namespace} 异常退出: {e}")
293
- if debug:
294
- traceback.print_exc()