jettask 0.2.1__py3-none-any.whl → 0.2.4__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/constants.py +213 -0
- jettask/core/app.py +525 -205
- jettask/core/cli.py +193 -185
- jettask/core/consumer_manager.py +126 -34
- jettask/core/context.py +3 -0
- jettask/core/enums.py +137 -0
- jettask/core/event_pool.py +501 -168
- jettask/core/message.py +147 -0
- jettask/core/offline_worker_recovery.py +181 -114
- jettask/core/task.py +10 -174
- jettask/core/task_batch.py +153 -0
- jettask/core/unified_manager_base.py +243 -0
- jettask/core/worker_scanner.py +54 -54
- jettask/executors/asyncio.py +184 -64
- jettask/webui/backend/config.py +51 -0
- jettask/webui/backend/data_access.py +2083 -92
- jettask/webui/backend/data_api.py +3294 -0
- jettask/webui/backend/dependencies.py +261 -0
- jettask/webui/backend/init_meta_db.py +158 -0
- jettask/webui/backend/main.py +1358 -69
- jettask/webui/backend/main_unified.py +78 -0
- jettask/webui/backend/main_v2.py +394 -0
- jettask/webui/backend/namespace_api.py +295 -0
- jettask/webui/backend/namespace_api_old.py +294 -0
- jettask/webui/backend/namespace_data_access.py +611 -0
- jettask/webui/backend/queue_backlog_api.py +727 -0
- jettask/webui/backend/queue_stats_v2.py +521 -0
- jettask/webui/backend/redis_monitor_api.py +476 -0
- jettask/webui/backend/unified_api_router.py +1601 -0
- jettask/webui/db_init.py +204 -32
- jettask/webui/frontend/package-lock.json +492 -1
- jettask/webui/frontend/package.json +4 -1
- jettask/webui/frontend/src/App.css +105 -7
- jettask/webui/frontend/src/App.jsx +49 -20
- jettask/webui/frontend/src/components/NamespaceSelector.jsx +166 -0
- jettask/webui/frontend/src/components/QueueBacklogChart.jsx +298 -0
- jettask/webui/frontend/src/components/QueueBacklogTrend.jsx +638 -0
- jettask/webui/frontend/src/components/QueueDetailsTable.css +65 -0
- jettask/webui/frontend/src/components/QueueDetailsTable.jsx +487 -0
- jettask/webui/frontend/src/components/QueueDetailsTableV2.jsx +465 -0
- jettask/webui/frontend/src/components/ScheduledTaskFilter.jsx +423 -0
- jettask/webui/frontend/src/components/TaskFilter.jsx +425 -0
- jettask/webui/frontend/src/components/TimeRangeSelector.css +21 -0
- jettask/webui/frontend/src/components/TimeRangeSelector.jsx +160 -0
- jettask/webui/frontend/src/components/layout/AppLayout.css +95 -0
- jettask/webui/frontend/src/components/layout/AppLayout.jsx +49 -0
- jettask/webui/frontend/src/components/layout/Header.css +34 -10
- jettask/webui/frontend/src/components/layout/Header.jsx +31 -23
- jettask/webui/frontend/src/components/layout/SideMenu.css +137 -0
- jettask/webui/frontend/src/components/layout/SideMenu.jsx +209 -0
- jettask/webui/frontend/src/components/layout/TabsNav.css +244 -0
- jettask/webui/frontend/src/components/layout/TabsNav.jsx +206 -0
- jettask/webui/frontend/src/components/layout/UserInfo.css +197 -0
- jettask/webui/frontend/src/components/layout/UserInfo.jsx +197 -0
- jettask/webui/frontend/src/contexts/NamespaceContext.jsx +72 -0
- jettask/webui/frontend/src/contexts/TabsContext.backup.jsx +245 -0
- jettask/webui/frontend/src/main.jsx +1 -0
- jettask/webui/frontend/src/pages/Alerts.jsx +684 -0
- jettask/webui/frontend/src/pages/Dashboard.jsx +1330 -0
- jettask/webui/frontend/src/pages/QueueDetail.jsx +1109 -10
- jettask/webui/frontend/src/pages/QueueMonitor.jsx +236 -115
- jettask/webui/frontend/src/pages/Queues.jsx +5 -1
- jettask/webui/frontend/src/pages/ScheduledTasks.jsx +809 -0
- jettask/webui/frontend/src/pages/Settings.jsx +800 -0
- jettask/webui/frontend/src/services/api.js +7 -5
- jettask/webui/frontend/src/utils/suppressWarnings.js +22 -0
- jettask/webui/frontend/src/utils/userPreferences.js +154 -0
- jettask/webui/multi_namespace_consumer.py +543 -0
- jettask/webui/pg_consumer.py +983 -246
- jettask/webui/static/dist/assets/index-7129cfe1.css +1 -0
- jettask/webui/static/dist/assets/index-8d1935cc.js +774 -0
- jettask/webui/static/dist/index.html +2 -2
- jettask/webui/task_center.py +216 -0
- jettask/webui/task_center_client.py +150 -0
- jettask/webui/unified_consumer_manager.py +193 -0
- {jettask-0.2.1.dist-info → jettask-0.2.4.dist-info}/METADATA +1 -1
- jettask-0.2.4.dist-info/RECORD +134 -0
- jettask/webui/pg_consumer_slow.py +0 -1099
- jettask/webui/pg_consumer_test.py +0 -678
- jettask/webui/static/dist/assets/index-823408e8.css +0 -1
- jettask/webui/static/dist/assets/index-9968b0b8.js +0 -543
- jettask/webui/test_pg_consumer_recovery.py +0 -547
- jettask/webui/test_recovery_simple.py +0 -492
- jettask/webui/test_self_recovery.py +0 -467
- jettask-0.2.1.dist-info/RECORD +0 -91
- {jettask-0.2.1.dist-info → jettask-0.2.4.dist-info}/WHEEL +0 -0
- {jettask-0.2.1.dist-info → jettask-0.2.4.dist-info}/entry_points.txt +0 -0
- {jettask-0.2.1.dist-info → jettask-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {jettask-0.2.1.dist-info → jettask-0.2.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,261 @@
|
|
1
|
+
"""
|
2
|
+
Dependency injection for JetTask WebUI Backend
|
3
|
+
"""
|
4
|
+
from typing import Optional, AsyncGenerator
|
5
|
+
from fastapi import Depends, HTTPException, Header
|
6
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
7
|
+
import redis.asyncio as redis
|
8
|
+
|
9
|
+
from core.database import db_manager, DatabaseManager
|
10
|
+
from core.cache import cache_manager, CacheManager
|
11
|
+
from core.exceptions import NamespaceNotFoundError, DatabaseConnectionError
|
12
|
+
from namespace_data_access import get_namespace_data_access
|
13
|
+
import logging
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
# 依赖注入函数
|
19
|
+
|
20
|
+
async def get_database_manager() -> DatabaseManager:
|
21
|
+
"""获取数据库管理器"""
|
22
|
+
return db_manager
|
23
|
+
|
24
|
+
|
25
|
+
async def get_cache_manager() -> CacheManager:
|
26
|
+
"""获取缓存管理器"""
|
27
|
+
return cache_manager
|
28
|
+
|
29
|
+
|
30
|
+
async def get_namespace_from_path(namespace: str = "default") -> str:
|
31
|
+
"""从路径参数获取命名空间"""
|
32
|
+
if not namespace:
|
33
|
+
raise HTTPException(status_code=400, detail="Namespace is required")
|
34
|
+
return namespace
|
35
|
+
|
36
|
+
|
37
|
+
async def get_namespace_from_header(
|
38
|
+
x_namespace: Optional[str] = Header(None, alias="X-Namespace")
|
39
|
+
) -> str:
|
40
|
+
"""从请求头获取命名空间"""
|
41
|
+
return x_namespace or "default"
|
42
|
+
|
43
|
+
|
44
|
+
async def get_current_namespace(
|
45
|
+
path_namespace: str = Depends(get_namespace_from_path),
|
46
|
+
header_namespace: str = Depends(get_namespace_from_header)
|
47
|
+
) -> str:
|
48
|
+
"""获取当前命名空间(优先使用路径参数)"""
|
49
|
+
return path_namespace if path_namespace != "default" else header_namespace
|
50
|
+
|
51
|
+
|
52
|
+
async def validate_namespace(namespace: str) -> str:
|
53
|
+
"""验证命名空间是否存在"""
|
54
|
+
try:
|
55
|
+
namespace_data_access = get_namespace_data_access()
|
56
|
+
# 尝试获取命名空间连接来验证其存在
|
57
|
+
conn = await namespace_data_access.manager.get_connection(namespace)
|
58
|
+
if not conn:
|
59
|
+
raise NamespaceNotFoundError(namespace)
|
60
|
+
return namespace
|
61
|
+
except Exception as e:
|
62
|
+
logger.error(f"命名空间验证失败 {namespace}: {e}")
|
63
|
+
raise NamespaceNotFoundError(namespace)
|
64
|
+
|
65
|
+
|
66
|
+
async def get_validated_namespace(
|
67
|
+
namespace: str = Depends(get_current_namespace)
|
68
|
+
) -> str:
|
69
|
+
"""获取并验证命名空间"""
|
70
|
+
return await validate_namespace(namespace)
|
71
|
+
|
72
|
+
|
73
|
+
async def get_pg_connection(
|
74
|
+
namespace: str = Depends(get_validated_namespace)
|
75
|
+
) -> AsyncGenerator[object, None]:
|
76
|
+
"""获取PostgreSQL连接"""
|
77
|
+
try:
|
78
|
+
namespace_data_access = get_namespace_data_access()
|
79
|
+
conn = await namespace_data_access.manager.get_connection(namespace)
|
80
|
+
|
81
|
+
if not conn.AsyncSessionLocal:
|
82
|
+
raise DatabaseConnectionError("PostgreSQL not configured for this namespace")
|
83
|
+
|
84
|
+
async with conn.AsyncSessionLocal() as session:
|
85
|
+
yield session
|
86
|
+
|
87
|
+
except DatabaseConnectionError:
|
88
|
+
raise
|
89
|
+
except Exception as e:
|
90
|
+
logger.error(f"获取PostgreSQL连接失败: {e}")
|
91
|
+
raise DatabaseConnectionError(f"PostgreSQL connection failed: {e}")
|
92
|
+
|
93
|
+
|
94
|
+
async def get_redis_client(
|
95
|
+
namespace: str = Depends(get_validated_namespace)
|
96
|
+
) -> AsyncGenerator[redis.Redis, None]:
|
97
|
+
"""获取Redis客户端"""
|
98
|
+
try:
|
99
|
+
namespace_data_access = get_namespace_data_access()
|
100
|
+
conn = await namespace_data_access.manager.get_connection(namespace)
|
101
|
+
|
102
|
+
redis_client = await conn.get_redis_client(decode=False)
|
103
|
+
|
104
|
+
try:
|
105
|
+
yield redis_client
|
106
|
+
finally:
|
107
|
+
await redis_client.aclose()
|
108
|
+
|
109
|
+
except Exception as e:
|
110
|
+
logger.error(f"获取Redis客户端失败: {e}")
|
111
|
+
raise DatabaseConnectionError(f"Redis connection failed: {e}")
|
112
|
+
|
113
|
+
|
114
|
+
async def get_namespace_connection(
|
115
|
+
namespace: str = Depends(get_validated_namespace)
|
116
|
+
):
|
117
|
+
"""获取命名空间连接对象"""
|
118
|
+
try:
|
119
|
+
namespace_data_access = get_namespace_data_access()
|
120
|
+
return await namespace_data_access.manager.get_connection(namespace)
|
121
|
+
except Exception as e:
|
122
|
+
logger.error(f"获取命名空间连接失败: {e}")
|
123
|
+
raise DatabaseConnectionError(f"Namespace connection failed: {e}")
|
124
|
+
|
125
|
+
|
126
|
+
# 权限和认证相关依赖(预留)
|
127
|
+
|
128
|
+
async def get_current_user(
|
129
|
+
authorization: Optional[str] = Header(None)
|
130
|
+
) -> Optional[dict]:
|
131
|
+
"""获取当前用户(预留接口)"""
|
132
|
+
# 这里可以实现JWT令牌解析、用户认证等逻辑
|
133
|
+
# 目前返回None表示匿名用户
|
134
|
+
return None
|
135
|
+
|
136
|
+
|
137
|
+
async def require_auth(
|
138
|
+
current_user: Optional[dict] = Depends(get_current_user)
|
139
|
+
) -> dict:
|
140
|
+
"""要求用户认证(预留接口)"""
|
141
|
+
# 这里可以实现认证检查逻辑
|
142
|
+
# 目前直接返回匿名用户
|
143
|
+
return current_user or {"id": "anonymous", "role": "user"}
|
144
|
+
|
145
|
+
|
146
|
+
async def require_admin(
|
147
|
+
current_user: dict = Depends(require_auth)
|
148
|
+
) -> dict:
|
149
|
+
"""要求管理员权限(预留接口)"""
|
150
|
+
# 这里可以实现权限检查逻辑
|
151
|
+
# 目前直接返回用户
|
152
|
+
return current_user
|
153
|
+
|
154
|
+
|
155
|
+
# 请求验证相关依赖
|
156
|
+
|
157
|
+
def validate_page_params(page: int = 1, page_size: int = 20) -> tuple[int, int]:
|
158
|
+
"""验证分页参数"""
|
159
|
+
if page < 1:
|
160
|
+
raise HTTPException(status_code=400, detail="Page must be >= 1")
|
161
|
+
if page_size < 1 or page_size > 100:
|
162
|
+
raise HTTPException(status_code=400, detail="Page size must be between 1 and 100")
|
163
|
+
return page, page_size
|
164
|
+
|
165
|
+
|
166
|
+
def validate_time_range(
|
167
|
+
start_time: Optional[str] = None,
|
168
|
+
end_time: Optional[str] = None,
|
169
|
+
time_range: Optional[str] = None
|
170
|
+
) -> dict:
|
171
|
+
"""验证时间范围参数"""
|
172
|
+
from datetime import datetime, timedelta
|
173
|
+
|
174
|
+
result = {}
|
175
|
+
|
176
|
+
if time_range:
|
177
|
+
# 预设时间范围
|
178
|
+
time_map = {
|
179
|
+
'15m': timedelta(minutes=15),
|
180
|
+
'30m': timedelta(minutes=30),
|
181
|
+
'1h': timedelta(hours=1),
|
182
|
+
'3h': timedelta(hours=3),
|
183
|
+
'6h': timedelta(hours=6),
|
184
|
+
'12h': timedelta(hours=12),
|
185
|
+
'24h': timedelta(hours=24),
|
186
|
+
'3d': timedelta(days=3),
|
187
|
+
'7d': timedelta(days=7),
|
188
|
+
'30d': timedelta(days=30)
|
189
|
+
}
|
190
|
+
|
191
|
+
if time_range not in time_map:
|
192
|
+
raise HTTPException(
|
193
|
+
status_code=400,
|
194
|
+
detail=f"Invalid time_range: {time_range}"
|
195
|
+
)
|
196
|
+
|
197
|
+
now = datetime.now()
|
198
|
+
result['end_time'] = now
|
199
|
+
result['start_time'] = now - time_map[time_range]
|
200
|
+
result['time_range'] = time_range
|
201
|
+
|
202
|
+
elif start_time or end_time:
|
203
|
+
# 自定义时间范围
|
204
|
+
try:
|
205
|
+
if start_time:
|
206
|
+
result['start_time'] = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
|
207
|
+
if end_time:
|
208
|
+
result['end_time'] = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
|
209
|
+
|
210
|
+
if result.get('start_time') and result.get('end_time'):
|
211
|
+
if result['start_time'] >= result['end_time']:
|
212
|
+
raise HTTPException(
|
213
|
+
status_code=400,
|
214
|
+
detail="start_time must be before end_time"
|
215
|
+
)
|
216
|
+
except ValueError as e:
|
217
|
+
raise HTTPException(
|
218
|
+
status_code=400,
|
219
|
+
detail=f"Invalid datetime format: {e}"
|
220
|
+
)
|
221
|
+
|
222
|
+
else:
|
223
|
+
# 默认最近1小时
|
224
|
+
now = datetime.now()
|
225
|
+
result['end_time'] = now
|
226
|
+
result['start_time'] = now - timedelta(hours=1)
|
227
|
+
result['time_range'] = '1h'
|
228
|
+
|
229
|
+
return result
|
230
|
+
|
231
|
+
|
232
|
+
# 性能监控相关依赖
|
233
|
+
|
234
|
+
class RequestMetrics:
|
235
|
+
"""请求指标收集器"""
|
236
|
+
|
237
|
+
def __init__(self):
|
238
|
+
self.start_time = None
|
239
|
+
self.namespace = None
|
240
|
+
self.endpoint = None
|
241
|
+
|
242
|
+
def start(self, namespace: str, endpoint: str):
|
243
|
+
import time
|
244
|
+
self.start_time = time.time()
|
245
|
+
self.namespace = namespace
|
246
|
+
self.endpoint = endpoint
|
247
|
+
|
248
|
+
def finish(self):
|
249
|
+
if self.start_time:
|
250
|
+
import time
|
251
|
+
duration = time.time() - self.start_time
|
252
|
+
logger.info(
|
253
|
+
f"API请求完成: {self.endpoint} "
|
254
|
+
f"namespace={self.namespace} "
|
255
|
+
f"duration={duration:.3f}s"
|
256
|
+
)
|
257
|
+
|
258
|
+
|
259
|
+
async def get_request_metrics() -> RequestMetrics:
|
260
|
+
"""获取请求指标收集器"""
|
261
|
+
return RequestMetrics()
|
@@ -0,0 +1,158 @@
|
|
1
|
+
"""
|
2
|
+
初始化任务中心元数据库
|
3
|
+
这个脚本用于创建任务中心自己的数据库和表结构
|
4
|
+
"""
|
5
|
+
import psycopg2
|
6
|
+
import sys
|
7
|
+
from config import task_center_config
|
8
|
+
import logging
|
9
|
+
|
10
|
+
logging.basicConfig(level=logging.INFO)
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
def create_meta_database():
|
15
|
+
"""创建任务中心元数据库"""
|
16
|
+
# 连接到postgres数据库来创建新数据库
|
17
|
+
conn = psycopg2.connect(
|
18
|
+
host=task_center_config.meta_db_host,
|
19
|
+
port=task_center_config.meta_db_port,
|
20
|
+
user=task_center_config.meta_db_user,
|
21
|
+
password=task_center_config.meta_db_password,
|
22
|
+
database='postgres'
|
23
|
+
)
|
24
|
+
conn.autocommit = True
|
25
|
+
cur = conn.cursor()
|
26
|
+
|
27
|
+
try:
|
28
|
+
# 检查数据库是否存在
|
29
|
+
cur.execute(
|
30
|
+
"SELECT 1 FROM pg_database WHERE datname = %s",
|
31
|
+
(task_center_config.meta_db_name,)
|
32
|
+
)
|
33
|
+
|
34
|
+
if not cur.fetchone():
|
35
|
+
# 创建数据库
|
36
|
+
cur.execute(f"CREATE DATABASE {task_center_config.meta_db_name}")
|
37
|
+
logger.info(f"Created database: {task_center_config.meta_db_name}")
|
38
|
+
else:
|
39
|
+
logger.info(f"Database already exists: {task_center_config.meta_db_name}")
|
40
|
+
|
41
|
+
finally:
|
42
|
+
cur.close()
|
43
|
+
conn.close()
|
44
|
+
|
45
|
+
|
46
|
+
def init_meta_tables():
|
47
|
+
"""初始化元数据表"""
|
48
|
+
conn = psycopg2.connect(task_center_config.sync_meta_database_url)
|
49
|
+
cur = conn.cursor()
|
50
|
+
|
51
|
+
try:
|
52
|
+
# 创建命名空间表
|
53
|
+
cur.execute("""
|
54
|
+
CREATE TABLE IF NOT EXISTS namespaces (
|
55
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
56
|
+
name VARCHAR(255) NOT NULL UNIQUE,
|
57
|
+
description TEXT,
|
58
|
+
-- JetTask应用使用的Redis配置
|
59
|
+
redis_config JSONB NOT NULL COMMENT 'JetTask应用的Redis配置',
|
60
|
+
-- JetTask应用使用的PostgreSQL配置
|
61
|
+
pg_config JSONB NOT NULL COMMENT 'JetTask应用的PostgreSQL配置',
|
62
|
+
is_active BOOLEAN DEFAULT true,
|
63
|
+
version INTEGER DEFAULT 1,
|
64
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
65
|
+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
66
|
+
);
|
67
|
+
""")
|
68
|
+
|
69
|
+
# 创建索引
|
70
|
+
cur.execute("CREATE INDEX IF NOT EXISTS idx_namespaces_name ON namespaces(name);")
|
71
|
+
cur.execute("CREATE INDEX IF NOT EXISTS idx_namespaces_is_active ON namespaces(is_active);")
|
72
|
+
cur.execute("CREATE INDEX IF NOT EXISTS idx_namespaces_version ON namespaces(version);")
|
73
|
+
|
74
|
+
# 创建更新时间触发器
|
75
|
+
cur.execute("""
|
76
|
+
CREATE OR REPLACE FUNCTION update_namespaces_updated_at()
|
77
|
+
RETURNS TRIGGER AS $$
|
78
|
+
BEGIN
|
79
|
+
NEW.updated_at = CURRENT_TIMESTAMP;
|
80
|
+
RETURN NEW;
|
81
|
+
END;
|
82
|
+
$$ LANGUAGE plpgsql;
|
83
|
+
""")
|
84
|
+
|
85
|
+
cur.execute("""
|
86
|
+
DO $$
|
87
|
+
BEGIN
|
88
|
+
IF NOT EXISTS (
|
89
|
+
SELECT 1 FROM pg_trigger
|
90
|
+
WHERE tgname = 'update_namespaces_updated_at'
|
91
|
+
) THEN
|
92
|
+
CREATE TRIGGER update_namespaces_updated_at
|
93
|
+
BEFORE UPDATE ON namespaces
|
94
|
+
FOR EACH ROW
|
95
|
+
EXECUTE FUNCTION update_namespaces_updated_at();
|
96
|
+
END IF;
|
97
|
+
END;
|
98
|
+
$$;
|
99
|
+
""")
|
100
|
+
|
101
|
+
# 插入默认命名空间
|
102
|
+
cur.execute("""
|
103
|
+
INSERT INTO namespaces (id, name, description, redis_config, pg_config)
|
104
|
+
VALUES (
|
105
|
+
'a8f10720-068b-4264-bcbb-e00ceba370e9',
|
106
|
+
'default',
|
107
|
+
'默认命名空间 - JetTask应用使用此配置',
|
108
|
+
'{"host": "localhost", "port": 6379, "password": null, "db": 0}',
|
109
|
+
'{"host": "localhost", "port": 5432, "user": "jettask", "password": "123456", "database": "jettask"}'
|
110
|
+
)
|
111
|
+
ON CONFLICT (name) DO NOTHING;
|
112
|
+
""")
|
113
|
+
|
114
|
+
conn.commit()
|
115
|
+
logger.info("Initialized meta tables successfully")
|
116
|
+
|
117
|
+
except Exception as e:
|
118
|
+
conn.rollback()
|
119
|
+
logger.error(f"Failed to initialize meta tables: {e}")
|
120
|
+
raise
|
121
|
+
finally:
|
122
|
+
cur.close()
|
123
|
+
conn.close()
|
124
|
+
|
125
|
+
|
126
|
+
def main():
|
127
|
+
"""主函数"""
|
128
|
+
logger.info("=" * 60)
|
129
|
+
logger.info("任务中心元数据库初始化")
|
130
|
+
logger.info("=" * 60)
|
131
|
+
logger.info(f"元数据库地址: {task_center_config.meta_db_host}:{task_center_config.meta_db_port}")
|
132
|
+
logger.info(f"元数据库名称: {task_center_config.meta_db_name}")
|
133
|
+
logger.info(f"元数据库用户: {task_center_config.meta_db_user}")
|
134
|
+
logger.info("-" * 60)
|
135
|
+
|
136
|
+
try:
|
137
|
+
# 1. 创建数据库
|
138
|
+
create_meta_database()
|
139
|
+
|
140
|
+
# 2. 初始化表结构
|
141
|
+
init_meta_tables()
|
142
|
+
|
143
|
+
logger.info("-" * 60)
|
144
|
+
logger.info("✅ 元数据库初始化完成!")
|
145
|
+
logger.info("")
|
146
|
+
logger.info("说明:")
|
147
|
+
logger.info("1. 任务中心元数据库用于存储命名空间配置")
|
148
|
+
logger.info("2. 每个命名空间定义了JetTask应用使用的Redis和PostgreSQL配置")
|
149
|
+
logger.info("3. JetTask应用通过命名空间ID获取其专用的数据库配置")
|
150
|
+
logger.info("=" * 60)
|
151
|
+
|
152
|
+
except Exception as e:
|
153
|
+
logger.error(f"初始化失败: {e}")
|
154
|
+
sys.exit(1)
|
155
|
+
|
156
|
+
|
157
|
+
if __name__ == "__main__":
|
158
|
+
main()
|