celestialflow 3.1.5__tar.gz → 3.1.6__tar.gz
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.
- {celestialflow-3.1.5 → celestialflow-3.1.6}/PKG-INFO +14 -9
- {celestialflow-3.1.5 → celestialflow-3.1.6}/README.md +13 -8
- {celestialflow-3.1.5 → celestialflow-3.1.6}/pyproject.toml +80 -74
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/__init__.py +17 -17
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/graph/__init__.py +3 -3
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/graph/core_graph.py +38 -26
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/graph/core_structure.py +3 -3
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/graph/util_analysis.py +4 -4
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/graph/util_serialize.py +4 -4
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/observability/__init__.py +1 -1
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/observability/core_report.py +45 -39
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/persistence/core_base.py +7 -6
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/persistence/core_fail.py +5 -2
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/persistence/core_log.py +17 -3
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/persistence/util_jsonl.py +1 -1
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/__init__.py +1 -1
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/core_metrics.py +4 -4
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/core_queue.py +14 -12
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/core_runner.py +39 -21
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/util_errors.py +1 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/util_estimators.py +2 -2
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/util_factories.py +5 -7
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/util_types.py +7 -5
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/stage/__init__.py +3 -3
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/stage/core_executor.py +46 -30
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/stage/core_stage.py +25 -13
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/stage/core_stages.py +21 -12
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/utils/util_benchmark.py +12 -1
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/utils/util_format.py +9 -9
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/config.json +4 -4
- celestialflow-3.1.5/src/celestialflow/web/server.py → celestialflow-3.1.6/src/celestialflow/web/core_server.py +86 -64
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/css/_colors.css +23 -18
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/css/base.css +74 -56
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/css/dashboard.css +73 -71
- celestialflow-3.1.6/src/celestialflow/web/static/css/errors.css +286 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/css/inject.css +124 -161
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/main.js +4 -4
- celestialflow-3.1.6/src/celestialflow/web/static/js/task_analysis.js +59 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_errors.js +62 -45
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_history.js +14 -8
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_injection.js +21 -16
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_statuses.js +6 -14
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_structure.js +9 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_topology.js +20 -20
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/utils.js +79 -15
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/main.ts +4 -4
- celestialflow-3.1.6/src/celestialflow/web/static/ts/task_analysis.ts +67 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/task_errors.ts +178 -161
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/task_history.ts +15 -9
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/task_injection.ts +9 -4
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/task_statuses.ts +12 -14
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/task_structure.ts +10 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/utils.ts +92 -14
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/templates/index.html +23 -19
- celestialflow-3.1.6/src/celestialflow/web/util_cal.py +4 -0
- celestialflow-3.1.6/src/celestialflow/web/util_config.py +23 -0
- celestialflow-3.1.6/src/celestialflow/web/util_error.py +53 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow.egg-info/PKG-INFO +14 -9
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow.egg-info/SOURCES.txt +6 -2
- celestialflow-3.1.6/src/celestialflow.egg-info/entry_points.txt +2 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/tests/test_executor.py +1 -1
- {celestialflow-3.1.5 → celestialflow-3.1.6}/tests/test_stages.py +23 -19
- {celestialflow-3.1.5 → celestialflow-3.1.6}/tests/test_structure.py +16 -13
- {celestialflow-3.1.5 → celestialflow-3.1.6}/tests/test_utils.py +234 -237
- celestialflow-3.1.5/src/celestialflow/web/static/css/errors.css +0 -284
- celestialflow-3.1.5/src/celestialflow/web/static/ts/task_topology.ts +0 -67
- celestialflow-3.1.5/src/celestialflow.egg-info/entry_points.txt +0 -2
- {celestialflow-3.1.5 → celestialflow-3.1.6}/setup.cfg +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/persistence/__init__.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/persistence/util_constant.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/core_envelope.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/core_progress.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/util_hash.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/runtime/util_queue.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/utils/__init__.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/utils/util_clone.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/utils/util_collections.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/utils/util_debug.py +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/favicon.ico +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_config.js +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/task_summary.js +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/js/web_config.js +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/globals.d.ts +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/task_summary.ts +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow/web/static/ts/web_config.ts +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow.egg-info/dependency_links.txt +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow.egg-info/requires.txt +0 -0
- {celestialflow-3.1.5 → celestialflow-3.1.6}/src/celestialflow.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: celestialflow
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.6
|
|
4
4
|
Summary: A flexible GRAPH-based task orchestration framework.
|
|
5
5
|
Author-email: Mr-xiaotian <mingxiaomingtian@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -254,22 +254,27 @@ flowchart TD
|
|
|
254
254
|
<p align="center">
|
|
255
255
|
<img src="https://raw.githubusercontent.com/Mr-xiaotian/CelestialFlow/main/img/file_structure.svg" alt="FileStructure" />
|
|
256
256
|
<br/>
|
|
257
|
-
<em>celestial-flow 3.1.
|
|
257
|
+
<em>celestial-flow 3.1.6</em>
|
|
258
258
|
</p>
|
|
259
259
|
|
|
260
260
|
(该视图由我的另一个项目[CelestialVault](https://github.com/Mr-xiaotian/CelestialVault)中inst_file.FileTree.print_tree()生成。转换为图片则借助[Carbon](https://carbon.now.sh)。)
|
|
261
261
|
|
|
262
262
|
## 版本日志(Version Log)
|
|
263
|
-
- 3.1.
|
|
263
|
+
- 3.1.6
|
|
264
264
|
- feat
|
|
265
|
-
-
|
|
266
|
-
-
|
|
265
|
+
- 前端现在只储存一页的error数据, 有效减少了运行大规模任务时前端内存飙升的问题;
|
|
266
|
+
- 优化任务数显示, 大于1*10^7时显示科学计数法, 否则显示英式计数;
|
|
267
|
+
- 优化小屏模式下表格的显示: 改为用卡片式显示;
|
|
268
|
+
- 在error表格中加入index项;
|
|
269
|
+
- 大幅调整任务颜色分配, 现在重复任务使用黄色系, 等待任务使用灰色系;
|
|
270
|
+
- 将节点卡片中的已消耗时间颜色拟合为下方进度条颜色;
|
|
267
271
|
- refactor
|
|
268
|
-
-
|
|
269
|
-
-
|
|
272
|
+
- 用mypy整理了一遍类型标注;
|
|
273
|
+
- 删除与整合部分css代码;
|
|
274
|
+
- 将字体等适合rem单位的地方全部从px替换为rem, 并且都部分size进行统一;
|
|
270
275
|
- fix
|
|
271
|
-
-
|
|
272
|
-
-
|
|
276
|
+
- 修复总体剩余时间在特殊情况下显示0的问题(这玩意真麻烦);
|
|
277
|
+
- 修复部分小屏下的显示问题, 但折线图不显示的问题不太好解决;
|
|
273
278
|
|
|
274
279
|
## Star 历史趋势(Star History)
|
|
275
280
|
|
|
@@ -229,22 +229,27 @@ flowchart TD
|
|
|
229
229
|
<p align="center">
|
|
230
230
|
<img src="https://raw.githubusercontent.com/Mr-xiaotian/CelestialFlow/main/img/file_structure.svg" alt="FileStructure" />
|
|
231
231
|
<br/>
|
|
232
|
-
<em>celestial-flow 3.1.
|
|
232
|
+
<em>celestial-flow 3.1.6</em>
|
|
233
233
|
</p>
|
|
234
234
|
|
|
235
235
|
(该视图由我的另一个项目[CelestialVault](https://github.com/Mr-xiaotian/CelestialVault)中inst_file.FileTree.print_tree()生成。转换为图片则借助[Carbon](https://carbon.now.sh)。)
|
|
236
236
|
|
|
237
237
|
## 版本日志(Version Log)
|
|
238
|
-
- 3.1.
|
|
238
|
+
- 3.1.6
|
|
239
239
|
- feat
|
|
240
|
-
-
|
|
241
|
-
-
|
|
240
|
+
- 前端现在只储存一页的error数据, 有效减少了运行大规模任务时前端内存飙升的问题;
|
|
241
|
+
- 优化任务数显示, 大于1*10^7时显示科学计数法, 否则显示英式计数;
|
|
242
|
+
- 优化小屏模式下表格的显示: 改为用卡片式显示;
|
|
243
|
+
- 在error表格中加入index项;
|
|
244
|
+
- 大幅调整任务颜色分配, 现在重复任务使用黄色系, 等待任务使用灰色系;
|
|
245
|
+
- 将节点卡片中的已消耗时间颜色拟合为下方进度条颜色;
|
|
242
246
|
- refactor
|
|
243
|
-
-
|
|
244
|
-
-
|
|
247
|
+
- 用mypy整理了一遍类型标注;
|
|
248
|
+
- 删除与整合部分css代码;
|
|
249
|
+
- 将字体等适合rem单位的地方全部从px替换为rem, 并且都部分size进行统一;
|
|
245
250
|
- fix
|
|
246
|
-
-
|
|
247
|
-
-
|
|
251
|
+
- 修复总体剩余时间在特殊情况下显示0的问题(这玩意真麻烦);
|
|
252
|
+
- 修复部分小屏下的显示问题, 但折线图不显示的问题不太好解决;
|
|
248
253
|
|
|
249
254
|
## Star 历史趋势(Star History)
|
|
250
255
|
|
|
@@ -1,74 +1,80 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "celestialflow"
|
|
7
|
-
version = "3.1.
|
|
8
|
-
description = "A flexible GRAPH-based task orchestration framework."
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
license = { text = "MIT" }
|
|
11
|
-
authors = [{ name = "Mr-xiaotian", email = "mingxiaomingtian@gmail.com" }]
|
|
12
|
-
keywords = ["workflow", "task", "graph", "async", "CelestialFlow"]
|
|
13
|
-
requires-python = ">=3.10"
|
|
14
|
-
|
|
15
|
-
dependencies = [
|
|
16
|
-
"tqdm",
|
|
17
|
-
"fastapi",
|
|
18
|
-
"uvicorn",
|
|
19
|
-
"requests",
|
|
20
|
-
"networkx",
|
|
21
|
-
"redis",
|
|
22
|
-
"jinja2",
|
|
23
|
-
"celestialtree>=0.1.2",
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
classifiers = [
|
|
27
|
-
"Programming Language :: Python :: 3",
|
|
28
|
-
"License :: OSI Approved :: MIT License",
|
|
29
|
-
"Operating System :: OS Independent",
|
|
30
|
-
"Framework :: FastAPI",
|
|
31
|
-
"Topic :: Software Development :: Libraries",
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
[project.urls]
|
|
35
|
-
"Homepage" = "https://github.com/Mr-xiaotian/CelestialFlow"
|
|
36
|
-
"Bug Tracker" = "https://github.com/Mr-xiaotian/CelestialFlow/issues"
|
|
37
|
-
|
|
38
|
-
[project.scripts]
|
|
39
|
-
celestialflow-web = "celestialflow.web.
|
|
40
|
-
|
|
41
|
-
[tool.setuptools]
|
|
42
|
-
license-files = []
|
|
43
|
-
|
|
44
|
-
[tool.setuptools.package-data]
|
|
45
|
-
celestialflow = [
|
|
46
|
-
"web/templates/**/*.html",
|
|
47
|
-
"web/static/**/*",
|
|
48
|
-
"web/config.json"
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
[tool.pytest.ini_options]
|
|
52
|
-
addopts = "-s"
|
|
53
|
-
log_cli = true
|
|
54
|
-
log_cli_level = "INFO"
|
|
55
|
-
log_cli_format = "%(asctime)s [%(levelname)s] %(message)s"
|
|
56
|
-
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
|
|
57
|
-
|
|
58
|
-
filterwarnings = [
|
|
59
|
-
"ignore::DeprecationWarning",
|
|
60
|
-
"ignore::pytest.PytestDeprecationWarning",
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
asyncio_default_fixture_loop_scope = "function"
|
|
64
|
-
|
|
65
|
-
[dependency-groups]
|
|
66
|
-
dev = [
|
|
67
|
-
"build>=1.2.2.post1",
|
|
68
|
-
"twine>=6.1.0",
|
|
69
|
-
"pytest>=8.3.4",
|
|
70
|
-
"pytest-asyncio>=0.25.3",
|
|
71
|
-
"httpx>=0.28.1",
|
|
72
|
-
"python-dotenv>=1.2.2",
|
|
73
|
-
"
|
|
74
|
-
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "celestialflow"
|
|
7
|
+
version = "3.1.6"
|
|
8
|
+
description = "A flexible GRAPH-based task orchestration framework."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [{ name = "Mr-xiaotian", email = "mingxiaomingtian@gmail.com" }]
|
|
12
|
+
keywords = ["workflow", "task", "graph", "async", "CelestialFlow"]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
|
|
15
|
+
dependencies = [
|
|
16
|
+
"tqdm",
|
|
17
|
+
"fastapi",
|
|
18
|
+
"uvicorn",
|
|
19
|
+
"requests",
|
|
20
|
+
"networkx",
|
|
21
|
+
"redis",
|
|
22
|
+
"jinja2",
|
|
23
|
+
"celestialtree>=0.1.2",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"License :: OSI Approved :: MIT License",
|
|
29
|
+
"Operating System :: OS Independent",
|
|
30
|
+
"Framework :: FastAPI",
|
|
31
|
+
"Topic :: Software Development :: Libraries",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
"Homepage" = "https://github.com/Mr-xiaotian/CelestialFlow"
|
|
36
|
+
"Bug Tracker" = "https://github.com/Mr-xiaotian/CelestialFlow/issues"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
celestialflow-web = "celestialflow.web.core_server:main_entry"
|
|
40
|
+
|
|
41
|
+
[tool.setuptools]
|
|
42
|
+
license-files = []
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.package-data]
|
|
45
|
+
celestialflow = [
|
|
46
|
+
"web/templates/**/*.html",
|
|
47
|
+
"web/static/**/*",
|
|
48
|
+
"web/config.json"
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
addopts = "-s"
|
|
53
|
+
log_cli = true
|
|
54
|
+
log_cli_level = "INFO"
|
|
55
|
+
log_cli_format = "%(asctime)s [%(levelname)s] %(message)s"
|
|
56
|
+
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
|
|
57
|
+
|
|
58
|
+
filterwarnings = [
|
|
59
|
+
"ignore::DeprecationWarning",
|
|
60
|
+
"ignore::pytest.PytestDeprecationWarning",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
64
|
+
|
|
65
|
+
[dependency-groups]
|
|
66
|
+
dev = [
|
|
67
|
+
"build>=1.2.2.post1",
|
|
68
|
+
"twine>=6.1.0",
|
|
69
|
+
"pytest>=8.3.4",
|
|
70
|
+
"pytest-asyncio>=0.25.3",
|
|
71
|
+
"httpx>=0.28.1",
|
|
72
|
+
"python-dotenv>=1.2.2",
|
|
73
|
+
"dill",
|
|
74
|
+
"mypy>=1.19.1",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[tool.mypy]
|
|
78
|
+
python_version = "3.10"
|
|
79
|
+
no_implicit_optional = false
|
|
80
|
+
disable_error_code = ["import-untyped"]
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
# __init__.py
|
|
2
|
-
from .stage import (
|
|
3
|
-
TaskExecutor,
|
|
4
|
-
TaskStage,
|
|
5
|
-
TaskSplitter,
|
|
6
|
-
TaskRedisTransport,
|
|
7
|
-
TaskRedisSource,
|
|
8
|
-
TaskRedisAck,
|
|
9
|
-
TaskRouter,
|
|
10
|
-
)
|
|
11
2
|
from .graph import (
|
|
12
|
-
TaskGraph,
|
|
13
3
|
TaskChain,
|
|
14
|
-
TaskLoop,
|
|
15
|
-
TaskCross,
|
|
16
4
|
TaskComplete,
|
|
17
|
-
|
|
5
|
+
TaskCross,
|
|
6
|
+
TaskGraph,
|
|
18
7
|
TaskGrid,
|
|
8
|
+
TaskLoop,
|
|
9
|
+
TaskWheel,
|
|
19
10
|
)
|
|
20
11
|
from .persistence.util_jsonl import (
|
|
21
12
|
load_jsonl_logs,
|
|
22
|
-
load_task_by_stage,
|
|
23
13
|
load_task_by_error,
|
|
14
|
+
load_task_by_stage,
|
|
24
15
|
)
|
|
25
|
-
from .runtime.util_types import TerminationSignal
|
|
26
16
|
from .runtime.util_hash import make_hashable
|
|
17
|
+
from .runtime.util_types import TerminationSignal
|
|
18
|
+
from .stage import (
|
|
19
|
+
TaskExecutor,
|
|
20
|
+
TaskRedisAck,
|
|
21
|
+
TaskRedisSource,
|
|
22
|
+
TaskRedisTransport,
|
|
23
|
+
TaskRouter,
|
|
24
|
+
TaskSplitter,
|
|
25
|
+
TaskStage,
|
|
26
|
+
)
|
|
27
|
+
from .utils.util_benchmark import benchmark_executor, benchmark_graph
|
|
27
28
|
from .utils.util_format import format_table
|
|
28
|
-
from .
|
|
29
|
-
from .web.server import TaskWebServer
|
|
29
|
+
from .web.core_server import TaskWebServer
|
|
30
30
|
|
|
31
31
|
__all__ = [
|
|
32
32
|
"TaskGraph",
|
|
@@ -1,40 +1,46 @@
|
|
|
1
1
|
# graph/core_graph.py
|
|
2
|
+
import multiprocessing
|
|
2
3
|
import time
|
|
3
4
|
import warnings
|
|
4
|
-
import multiprocessing
|
|
5
5
|
from collections import defaultdict, deque
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
6
8
|
from multiprocessing import Queue as MPQueue
|
|
7
9
|
|
|
8
10
|
from celestialtree import (
|
|
9
11
|
Client as CelestialTreeClient,
|
|
12
|
+
)
|
|
13
|
+
from celestialtree import (
|
|
10
14
|
NullClient as NullCelestialTreeClient,
|
|
15
|
+
)
|
|
16
|
+
from celestialtree import (
|
|
11
17
|
format_descendants_forest,
|
|
12
18
|
format_provenance_forest,
|
|
13
19
|
)
|
|
20
|
+
from networkx import is_directed_acyclic_graph
|
|
14
21
|
|
|
15
|
-
from ..
|
|
22
|
+
from ..observability import NullTaskReporter, TaskReporter
|
|
23
|
+
from ..persistence import FailListener, FailSinker, LogListener, LogSinker
|
|
24
|
+
from ..persistence.util_jsonl import load_task_by_error, load_task_by_stage
|
|
25
|
+
from ..runtime import TaskEnvelope, TaskInQueue, TaskOutQueue
|
|
26
|
+
from ..runtime.util_errors import UnconsumedError
|
|
16
27
|
from ..runtime.util_estimators import (
|
|
17
28
|
calc_elapsed,
|
|
18
|
-
calc_remaining,
|
|
19
29
|
calc_global_remain_equal_pred,
|
|
30
|
+
calc_remaining,
|
|
20
31
|
)
|
|
21
|
-
from ..runtime.util_errors import UnconsumedError
|
|
22
32
|
from ..runtime.util_types import (
|
|
33
|
+
NULL_PREV_STAGE,
|
|
34
|
+
STAGE_STYLE,
|
|
23
35
|
StageStatus,
|
|
24
36
|
TerminationSignal,
|
|
25
|
-
STAGE_STYLE,
|
|
26
|
-
NULL_PREV_STAGE,
|
|
27
37
|
)
|
|
28
38
|
from ..stage import TaskStage
|
|
29
|
-
from ..observability import TaskReporter, NullTaskReporter
|
|
30
|
-
from ..persistence import FailListener, FailSinker, LogListener, LogSinker
|
|
31
|
-
from ..persistence.util_jsonl import load_task_by_stage, load_task_by_error
|
|
32
39
|
from ..utils.util_collections import cluster_by_value_sorted
|
|
33
40
|
from ..utils.util_format import format_avg_time
|
|
34
41
|
from .util_analysis import (
|
|
35
|
-
format_networkx_graph,
|
|
36
42
|
compute_node_levels,
|
|
37
|
-
|
|
43
|
+
format_networkx_graph,
|
|
38
44
|
)
|
|
39
45
|
from .util_serialize import build_structure_graph, format_structure_list_from_graph
|
|
40
46
|
|
|
@@ -102,15 +108,15 @@ class TaskGraph:
|
|
|
102
108
|
# 用于保存所有子进程的引用
|
|
103
109
|
self.processes: list[multiprocessing.Process] = []
|
|
104
110
|
# 用于保存每个节点的运行信息
|
|
105
|
-
self.stage_runtime_dict: dict[str, dict] = defaultdict(dict)
|
|
111
|
+
self.stage_runtime_dict: dict[str, dict[str, Any]] = defaultdict(dict)
|
|
106
112
|
# 用于保存每个节点的上一次collect_runtime_snapshot()的状态信息
|
|
107
|
-
self.status_dict: dict[str, dict] = defaultdict(dict)
|
|
113
|
+
self.status_dict: dict[str, dict[str, Any]] = defaultdict(dict)
|
|
108
114
|
# 用于保存任务图的摘要信息
|
|
109
115
|
self.graph_summary: dict[str, int | float] = {}
|
|
110
116
|
# 用于保存每个节点的历史状态信息列表(仅保留最近20条)
|
|
111
117
|
self.stage_history: dict[str, list[dict]] = {}
|
|
112
118
|
# 用于保存每个节点的输入任务ID集合
|
|
113
|
-
self.input_ids: dict[str, set] = defaultdict(set)
|
|
119
|
+
self.input_ids: dict[str, set[int]] = defaultdict(set)
|
|
114
120
|
|
|
115
121
|
def init_listener(self) -> None:
|
|
116
122
|
"""
|
|
@@ -164,11 +170,11 @@ class TaskGraph:
|
|
|
164
170
|
queue.extend(stage.next_stages)
|
|
165
171
|
|
|
166
172
|
for stage_tag, stage_runtime in self.stage_runtime_dict.items():
|
|
167
|
-
|
|
173
|
+
current_stage: TaskStage = stage_runtime["stage"]
|
|
168
174
|
in_queue: TaskInQueue = stage_runtime["in_queue"]
|
|
169
175
|
|
|
170
176
|
# 遍历每个前驱,创建边队列
|
|
171
|
-
for prev_stage in
|
|
177
|
+
for prev_stage in current_stage.prev_stages:
|
|
172
178
|
prev_stage_tag = prev_stage.get_tag()
|
|
173
179
|
in_queue.add_source_tag(prev_stage_tag)
|
|
174
180
|
|
|
@@ -235,6 +241,7 @@ class TaskGraph:
|
|
|
235
241
|
self._is_report = is_report
|
|
236
242
|
self._report_host = host
|
|
237
243
|
self._report_port = port
|
|
244
|
+
self.reporter: TaskReporter | NullTaskReporter
|
|
238
245
|
if is_report:
|
|
239
246
|
self.reporter = TaskReporter(
|
|
240
247
|
host=host,
|
|
@@ -291,7 +298,7 @@ class TaskGraph:
|
|
|
291
298
|
:param execution_mode: 节点内部执行模式, 可选值为 'serial' 或 'thread''
|
|
292
299
|
"""
|
|
293
300
|
|
|
294
|
-
def set_subsequent_stage_mode(stage: TaskStage):
|
|
301
|
+
def set_subsequent_stage_mode(stage: TaskStage) -> None:
|
|
295
302
|
stage.set_stage_mode(stage_mode)
|
|
296
303
|
stage.set_execution_mode(execution_mode)
|
|
297
304
|
visited_stages.add(stage)
|
|
@@ -301,7 +308,7 @@ class TaskGraph:
|
|
|
301
308
|
continue
|
|
302
309
|
set_subsequent_stage_mode(next_stage)
|
|
303
310
|
|
|
304
|
-
visited_stages = set()
|
|
311
|
+
visited_stages: set[TaskStage] = set()
|
|
305
312
|
for root_stage in self.root_stages:
|
|
306
313
|
set_subsequent_stage_mode(root_stage)
|
|
307
314
|
self.init_analysis()
|
|
@@ -494,11 +501,11 @@ class TaskGraph:
|
|
|
494
501
|
|
|
495
502
|
# 收集并持久化每个 stage 中未消费的任务
|
|
496
503
|
for stage_tag, stage_runtime in self.stage_runtime_dict.items():
|
|
497
|
-
|
|
504
|
+
current_stage: TaskStage = stage_runtime["stage"]
|
|
498
505
|
in_queue: TaskInQueue = stage_runtime["in_queue"]
|
|
499
506
|
|
|
500
507
|
remaining_sources = in_queue.drain()
|
|
501
|
-
|
|
508
|
+
current_stage.metrics.add_error_count(len(remaining_sources))
|
|
502
509
|
|
|
503
510
|
# 持久化逻辑
|
|
504
511
|
for source in remaining_sources:
|
|
@@ -507,7 +514,7 @@ class TaskGraph:
|
|
|
507
514
|
error_id = self.ctree_client.emit(
|
|
508
515
|
"task.error",
|
|
509
516
|
[task_id],
|
|
510
|
-
payload=
|
|
517
|
+
payload=current_stage.get_summary(),
|
|
511
518
|
)
|
|
512
519
|
|
|
513
520
|
self.fail_sinker.task_error(
|
|
@@ -515,8 +522,8 @@ class TaskGraph:
|
|
|
515
522
|
)
|
|
516
523
|
|
|
517
524
|
self.log_sinker.task_error(
|
|
518
|
-
|
|
519
|
-
|
|
525
|
+
current_stage.get_func_name(),
|
|
526
|
+
current_stage.get_task_repr(task),
|
|
520
527
|
UnconsumedError(),
|
|
521
528
|
task_id,
|
|
522
529
|
error_id,
|
|
@@ -644,6 +651,9 @@ class TaskGraph:
|
|
|
644
651
|
def get_fail_by_error_dict(self) -> dict:
|
|
645
652
|
return load_task_by_error(self.fail_listener.jsonl_path)
|
|
646
653
|
|
|
654
|
+
def get_total_error_num(self) -> int:
|
|
655
|
+
return self.fail_listener.total_error_num
|
|
656
|
+
|
|
647
657
|
def get_status_dict(self) -> dict[str, dict]:
|
|
648
658
|
"""
|
|
649
659
|
获取任务链的状态字典
|
|
@@ -660,9 +670,9 @@ class TaskGraph:
|
|
|
660
670
|
"""获取任务链的历史状态信息字典"""
|
|
661
671
|
return self.stage_history
|
|
662
672
|
|
|
663
|
-
def
|
|
673
|
+
def get_graph_analysis(self) -> dict:
|
|
664
674
|
"""
|
|
665
|
-
|
|
675
|
+
获取任务图的分析信息
|
|
666
676
|
"""
|
|
667
677
|
return {
|
|
668
678
|
"isDAG": self.isDAG,
|
|
@@ -693,7 +703,9 @@ class TaskGraph:
|
|
|
693
703
|
"""
|
|
694
704
|
获取失败任务的回退路径
|
|
695
705
|
"""
|
|
696
|
-
|
|
706
|
+
if self.fail_listener.jsonl_path is None:
|
|
707
|
+
return ""
|
|
708
|
+
return str(Path(self.fail_listener.jsonl_path).resolve())
|
|
697
709
|
|
|
698
710
|
def get_stage_input_trace(self, stage_tag: str) -> str:
|
|
699
711
|
"""
|
|
@@ -67,7 +67,7 @@ class TaskCross(TaskGraph):
|
|
|
67
67
|
stage.set_graph_context(
|
|
68
68
|
next_stages=next_layer,
|
|
69
69
|
stage_mode="process",
|
|
70
|
-
stage_name=f"Layer{i+1}-{index+1}",
|
|
70
|
+
stage_name=f"Layer{i + 1}-{index + 1}",
|
|
71
71
|
)
|
|
72
72
|
super().__init__(
|
|
73
73
|
root_stages=layers[0], schedule_mode=schedule_mode, log_level=log_level
|
|
@@ -112,7 +112,7 @@ class TaskGrid(TaskGraph):
|
|
|
112
112
|
nexts.append(grid[i + 1][j]) # down
|
|
113
113
|
if j + 1 < cols:
|
|
114
114
|
nexts.append(grid[i][j + 1]) # right
|
|
115
|
-
curr.set_graph_context(nexts, "process", f"Grid-{i+1}-{j+1}")
|
|
115
|
+
curr.set_graph_context(nexts, "process", f"Grid-{i + 1}-{j + 1}")
|
|
116
116
|
super().__init__(
|
|
117
117
|
root_stages=[grid[0][0]], schedule_mode=schedule_mode, log_level=log_level
|
|
118
118
|
) # 起点为左上角
|
|
@@ -175,7 +175,7 @@ class TaskWheel(TaskGraph):
|
|
|
175
175
|
# 环相连(成闭环)
|
|
176
176
|
for i, node in enumerate(ring):
|
|
177
177
|
next_stage = ring[(i + 1) % len(ring)]
|
|
178
|
-
node.set_graph_context([next_stage], "process", f"Ring-{i+1}")
|
|
178
|
+
node.set_graph_context([next_stage], "process", f"Ring-{i + 1}")
|
|
179
179
|
super().__init__(root_stages=[center], log_level=log_level)
|
|
180
180
|
|
|
181
181
|
def start_wheel(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# graph/util_analysis.py
|
|
2
|
-
import networkx as nx
|
|
3
|
-
from networkx import is_directed_acyclic_graph
|
|
4
2
|
from typing import Any
|
|
5
3
|
|
|
4
|
+
import networkx as nx
|
|
5
|
+
|
|
6
6
|
|
|
7
7
|
# ======== (图论分析) ========
|
|
8
8
|
def format_networkx_graph(structure_graph: list[dict[str, Any]]) -> nx.DiGraph:
|
|
@@ -15,11 +15,11 @@ def format_networkx_graph(structure_graph: list[dict[str, Any]]) -> nx.DiGraph:
|
|
|
15
15
|
G = nx.DiGraph()
|
|
16
16
|
|
|
17
17
|
def add_node_and_edges(node: dict[str, Any]):
|
|
18
|
-
node_id = f
|
|
18
|
+
node_id = f"{node['name']}[{node['func_name']}]"
|
|
19
19
|
G.add_node(node_id, **{"mode": node.get("stage_mode")})
|
|
20
20
|
|
|
21
21
|
for child in node.get("next_stages", []):
|
|
22
|
-
child_id = f
|
|
22
|
+
child_id = f"{child['name']}[{child['func_name']}]"
|
|
23
23
|
G.add_edge(node_id, child_id)
|
|
24
24
|
# 递归添加子节点
|
|
25
25
|
add_node_and_edges(child)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# graph/util_serialize.py
|
|
2
|
-
from typing import TYPE_CHECKING,
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Set
|
|
3
3
|
|
|
4
4
|
if TYPE_CHECKING:
|
|
5
5
|
from ..stage import TaskStage
|
|
@@ -49,7 +49,7 @@ def _build_structure_subgraph(
|
|
|
49
49
|
return node
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def format_structure_list_from_graph(root_roots: List[Dict] = None) -> List[str]:
|
|
52
|
+
def format_structure_list_from_graph(root_roots: List[Dict] | None = None) -> List[str]:
|
|
53
53
|
"""
|
|
54
54
|
从多个 JSON 图结构生成格式化任务结构文本列表(带边框)
|
|
55
55
|
|
|
@@ -64,7 +64,7 @@ def format_structure_list_from_graph(root_roots: List[Dict] = None) -> List[str]
|
|
|
64
64
|
S = node.get("stage_mode", "?") # S
|
|
65
65
|
E = node.get("execution_mode", "?") # E
|
|
66
66
|
|
|
67
|
-
return f"{N}::{F}
|
|
67
|
+
return f"{N}::{F} (S:{S}, E:{E}){visited_note}"
|
|
68
68
|
|
|
69
69
|
# 只渲染“子节点”(有父节点)——保证一定画连接符
|
|
70
70
|
def build_child_lines(node: Dict, prefix: str, is_last: bool) -> List[str]:
|
|
@@ -88,7 +88,7 @@ def format_structure_list_from_graph(root_roots: List[Dict] = None) -> List[str]
|
|
|
88
88
|
lines.extend(build_child_lines(child, "", i == len(next_stages) - 1))
|
|
89
89
|
return lines
|
|
90
90
|
|
|
91
|
-
all_lines = []
|
|
91
|
+
all_lines: list[str] = []
|
|
92
92
|
for root in root_roots or []:
|
|
93
93
|
if all_lines:
|
|
94
94
|
all_lines.append("") # 根之间留空行
|