celestialflow 3.2.2__tar.gz → 3.2.3__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.2.2 → celestialflow-3.2.3}/PKG-INFO +51 -21
- {celestialflow-3.2.2 → celestialflow-3.2.3}/README.md +48 -18
- {celestialflow-3.2.2 → celestialflow-3.2.3}/pyproject.toml +4 -7
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/graph/core_graph.py +69 -85
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/graph/core_structure.py +22 -16
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/graph/util_analysis.py +3 -6
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/graph/util_serialize.py +6 -9
- celestialflow-3.2.3/src/celestialflow/graph/util_types.py +27 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/observability/core_progress.py +1 -1
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/observability/core_report.py +20 -21
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/persistence/core_fail.py +27 -9
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/persistence/core_log.py +15 -18
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/persistence/core_success.py +7 -6
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/persistence/util_jsonl.py +14 -29
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/core_dispatch.py +35 -15
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/core_envelope.py +16 -10
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/core_metrics.py +50 -40
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/core_queue.py +20 -13
- celestialflow-3.2.3/src/celestialflow/runtime/util_constant.py +19 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/util_estimators.py +14 -18
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/util_types.py +47 -42
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/stage/core_executor.py +83 -129
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/stage/core_stage.py +41 -10
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/stage/core_stages.py +103 -77
- celestialflow-3.2.3/src/celestialflow/stage/util_types.py +6 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/utils/util_benchmark.py +5 -3
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/utils/util_clone.py +22 -15
- celestialflow-3.2.3/src/celestialflow/web/config.json +34 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/core_server.py +219 -217
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/routes/pull_routes.py +5 -7
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/routes/push_routes.py +13 -9
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/css/base.css +0 -38
- celestialflow-3.2.3/src/celestialflow/web/static/css/dashboard.css +175 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/dashboard_analysis.css +41 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/dashboard_history.css +89 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/dashboard_statuses.css +225 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/dashboard_structure.css +27 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/dashboard_summary.css +136 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/errors.css +364 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/injection_editor.css +223 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/injection_layout.css +119 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/injection_nodes.css +92 -0
- celestialflow-3.2.3/src/celestialflow/web/static/css/injection_preview.css +140 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/dashboard_analysis.js +27 -10
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/dashboard_history.js +48 -34
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/dashboard_statuses.js +64 -47
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/dashboard_structure.js +28 -16
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/dashboard_summary.js +8 -7
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/errors.js +48 -25
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/i18n.js +145 -87
- celestialflow-3.2.3/src/celestialflow/web/static/js/injection.js +675 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/layout_editor.js +58 -26
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/main.js +56 -14
- celestialflow-3.2.3/src/celestialflow/web/static/js/utils.js +177 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/js/web_config.js +269 -118
- celestialflow-3.2.3/src/celestialflow/web/static/ts/dashboard_analysis.ts +95 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/dashboard_history.ts +63 -52
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/dashboard_statuses.ts +85 -56
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/dashboard_structure.ts +88 -80
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/dashboard_summary.ts +8 -8
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/errors.ts +74 -34
- celestialflow-3.2.3/src/celestialflow/web/static/ts/globals.d.ts +155 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/i18n.ts +173 -91
- celestialflow-3.2.3/src/celestialflow/web/static/ts/injection.ts +787 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/layout_editor.ts +70 -37
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/main.ts +135 -89
- celestialflow-3.2.3/src/celestialflow/web/static/ts/utils.ts +205 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/ts/web_config.ts +557 -357
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/templates/index.html +192 -215
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/util_error.py +29 -27
- celestialflow-3.2.3/src/celestialflow/web/util_models.py +96 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow.egg-info/PKG-INFO +51 -21
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow.egg-info/SOURCES.txt +7 -2
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow.egg-info/requires.txt +1 -1
- celestialflow-3.2.2/src/celestialflow/persistence/util_constant.py +0 -12
- celestialflow-3.2.2/src/celestialflow/web/config.json +0 -23
- celestialflow-3.2.2/src/celestialflow/web/static/css/dashboard.css +0 -71
- celestialflow-3.2.2/src/celestialflow/web/static/css/dashboard_analysis.css +0 -39
- celestialflow-3.2.2/src/celestialflow/web/static/css/dashboard_history.css +0 -87
- celestialflow-3.2.2/src/celestialflow/web/static/css/dashboard_statuses.css +0 -238
- celestialflow-3.2.2/src/celestialflow/web/static/css/dashboard_structure.css +0 -25
- celestialflow-3.2.2/src/celestialflow/web/static/css/dashboard_summary.css +0 -134
- celestialflow-3.2.2/src/celestialflow/web/static/css/errors.css +0 -315
- celestialflow-3.2.2/src/celestialflow/web/static/css/injection.css +0 -615
- celestialflow-3.2.2/src/celestialflow/web/static/js/injection.js +0 -404
- celestialflow-3.2.2/src/celestialflow/web/static/js/utils.js +0 -117
- celestialflow-3.2.2/src/celestialflow/web/static/ts/dashboard_analysis.ts +0 -70
- celestialflow-3.2.2/src/celestialflow/web/static/ts/globals.d.ts +0 -27
- celestialflow-3.2.2/src/celestialflow/web/static/ts/injection.ts +0 -455
- celestialflow-3.2.2/src/celestialflow/web/static/ts/utils.ts +0 -132
- celestialflow-3.2.2/src/celestialflow/web/util_models.py +0 -72
- {celestialflow-3.2.2 → celestialflow-3.2.3}/setup.cfg +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/funnel/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/funnel/core_inlet.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/funnel/core_spout.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/graph/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/observability/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/observability/core_observer.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/persistence/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/util_errors.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/runtime/util_hash.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/stage/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/utils/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/utils/util_collections.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/utils/util_format.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/routes/__init__.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/css/_colors.css +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/static/favicon.ico +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/util_cal.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow/web/util_config.py +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow.egg-info/dependency_links.txt +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/src/celestialflow.egg-info/entry_points.txt +0 -0
- {celestialflow-3.2.2 → celestialflow-3.2.3}/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.2.
|
|
3
|
+
Version: 3.2.3
|
|
4
4
|
Summary: A flexible GRAPH-based task orchestration framework.
|
|
5
5
|
Author-email: Mr-xiaotian <mingxiaomingtian@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -12,7 +12,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Framework :: FastAPI
|
|
14
14
|
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
-
Requires-Python: >=3.
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
Requires-Dist: tqdm
|
|
18
18
|
Requires-Dist: fastapi
|
|
@@ -21,7 +21,7 @@ Requires-Dist: requests
|
|
|
21
21
|
Requires-Dist: networkx
|
|
22
22
|
Requires-Dist: redis
|
|
23
23
|
Requires-Dist: jinja2
|
|
24
|
-
Requires-Dist: celestialtree>=0.1.
|
|
24
|
+
Requires-Dist: celestialtree>=0.1.3
|
|
25
25
|
|
|
26
26
|
# CelestialFlow ——一个轻量级、可并行、基于图结构的 Python 任务调度框架
|
|
27
27
|
|
|
@@ -240,12 +240,12 @@ flowchart TD
|
|
|
240
240
|
|
|
241
241
|
## 环境要求(Requirements)
|
|
242
242
|
|
|
243
|
-
**CelestialFlow** 基于 Python 3.
|
|
243
|
+
**CelestialFlow** 基于 Python 3.12+,并依赖以下核心组件。
|
|
244
244
|
请确保你的环境能够正常安装这些依赖(`pip install celestialflow` 会自动安装)。
|
|
245
245
|
|
|
246
246
|
| 依赖包 | 说明 |
|
|
247
247
|
| ----------------- | ---- |
|
|
248
|
-
| **Python ≥ 3.
|
|
248
|
+
| **Python ≥ 3.12** | 运行环境,建议使用 3.12 及以上版本 |
|
|
249
249
|
| **fastapi** | Web 服务接口框架(用于任务可视化与远程控制) |
|
|
250
250
|
| **uvicorn** | FastAPI 的高性能 ASGI 服务器 |
|
|
251
251
|
| **requests** | HTTP 客户端库,用于任务状态上报与远程调用 |
|
|
@@ -260,31 +260,61 @@ flowchart TD
|
|
|
260
260
|
<p align="center">
|
|
261
261
|
<img src="https://raw.githubusercontent.com/Mr-xiaotian/CelestialFlow/main/img/file_structure.svg" alt="FileStructure" />
|
|
262
262
|
<br/>
|
|
263
|
-
<em>celestial-flow 3.2.
|
|
263
|
+
<em>celestial-flow 3.2.3</em>
|
|
264
264
|
</p>
|
|
265
265
|
|
|
266
266
|
(该视图由我的另一个项目[CelestialVault](https://github.com/Mr-xiaotian/CelestialVault)中inst_file.FileTree.print_tree()生成。转换为图片则借助[Carbon](https://carbon.now.sh)。)
|
|
267
267
|
|
|
268
268
|
## 版本日志(Version Log)
|
|
269
|
-
- 3.2.
|
|
269
|
+
- 3.2.3
|
|
270
270
|
- feat:
|
|
271
|
-
-
|
|
272
|
-
|
|
273
|
-
-
|
|
271
|
+
- **[IMPORTANT]** 前端仪表盘设置面板中新添 `节点等待使用全局估计` 开关, 开启后节点卡片中原 `等待` 量将被替换为 `全局等待`, 并在卡片中显示 `全局剩余时间`
|
|
272
|
+
- 这个功能非常有趣, 开启前后能看到数值大幅波动
|
|
273
|
+
- **[IMPORTANT]** 重写任务注入页面, 现在实用性远远高于之前版本
|
|
274
|
+
- 可以给每个节点单独配置注入任务列表, 在一起发送
|
|
275
|
+
- **[IMPORTANT]** 移除 `TaskExecutor` 中 `get_args` 与 `process_result` 两个方法, 以及 `unpack_task_args` 属性
|
|
276
|
+
- 这是为引入泛型必要的修改
|
|
277
|
+
- `process_result` 功能很简单, 对func输出的result进行再次处理, 但事实上在输入func前对齐进行包装也能达到一样的效果
|
|
278
|
+
- `get_args` 功能更为复杂, 可以直接将前一节点提供的 `result` 转为当前节点所需的 `task` 类型, 非常灵活; 但问题在于太过灵活, 导致使用心智负担很大
|
|
279
|
+
- `unpack_task_args` 就是 `get_args` 带来的一项心智负担, 默认 `get_args` 会把 `task` 进行 `(task, )` 包裹后发送给func, 开启 `unpack_task_args` 后则直接发送
|
|
280
|
+
- **[IMPORTANT]** `graph` 的init参数中添加 `name`, 以与 `executor` `stage` 一致
|
|
281
|
+
- 破坏接口破坏性更新
|
|
282
|
+
- 在日志的 `start_graph` `end_graph` 与web端的 `graph_anaylysis` 中都有显示
|
|
283
|
+
- 彻底移除前后端通信中的 `graph_summary` , 原本残余的 `全局剩余时间` 现在拆为各个节点的 `全局等待` 与 `全局剩余时间`
|
|
284
|
+
- 这里所说的 `全局` 意为根据图论关系, 由上游剩余的任务数估算下游总共能获得多少任务
|
|
285
|
+
- 例如: 图关系 `A -> B`, A已处理任务2, 未处理任务3, B已处理任务4, 未处理任务2. 这意味着A成功的2个任务为B带来总共了6个任务, 那么我们可以据此估计B总功能获取"3/2*6=9"个任务, 因此B的 `等待` 任务数量为2, 但 `全局等待` 任务数量为5
|
|
286
|
+
- 前端中添加部分提示气泡, 鼠标放上去后可以介绍相关信息, 例如本次新加入的节点 `全局等待` 的含义
|
|
287
|
+
- 移除前端中节点卡片的拖拽功能
|
|
288
|
+
- 这个功能是在最早加入web页面时添加的, 当时感觉很帅, 但现在有点玩腻了
|
|
289
|
+
- 前端错误日志页面添加 `任务注入` 按钮, 可以把选定任务直接添加到任务注入页面中节点的代注入任务列表中
|
|
290
|
+
- 在 `TaskSplitter` 中添加 `split_item` 方法, 可自由定义
|
|
291
|
+
- 原本的 `splitter` 非常依赖于 `get_args`, 现在通过 `split_item` 方法稍微弥补其缺失的灵活性
|
|
274
292
|
- refactor:
|
|
275
|
-
-
|
|
276
|
-
|
|
293
|
+
- **[IMPORTANT]** 引入泛型, 同时强制性要求py版本>=3.12
|
|
294
|
+
- 泛型的引入使得代码更加类型安全, 同时也提高了代码的可读性
|
|
295
|
+
- 3.12版本对泛型的表述非常直观
|
|
296
|
+
- 移除前端代码中所有对 `localStorage` 的使用
|
|
297
|
+
- 在已经有config配置文件的情况下意义不大, 反而会带来困扰
|
|
298
|
+
- 将任务队列的drain操作从graph层移至stage层
|
|
299
|
+
- 之前不能这样做是因为节点的 `stage_mode` 可能为 `process`, 此时在主进程持有的节点非真实运行的节点
|
|
300
|
+
- 算是3.2.0版本带来的持久影响之一
|
|
301
|
+
- 优化 `TaskMetric` 中对锁的使用
|
|
302
|
+
- 移除 `TaskEnvelope` 中的 `change_id()` 方法, 现在默认envelope不可变, 同时 `emit_retry_envelope` 中不再把原有的envelope的id修改后继续提交给worker, 而是直接使用新生成的envelope
|
|
303
|
+
- 移除错误日志中的 `error` `error_repr` `task_repr` 字段
|
|
304
|
+
- 修改前后端通信中任务注入数据的格式, 以方便同时提交多个节点的任务数据
|
|
305
|
+
- 前端代码中开启strict检查
|
|
306
|
+
- 将前端中 `injection.css` 文件拆分成多个文件
|
|
307
|
+
- 修改 `config.json` 的数据格式, 现在按照生效区域进行分类
|
|
308
|
+
- 收紧前端中的数据类型
|
|
309
|
+
- 添加 `ReportTaskGraph` 类型, 专门用于给reporter做类型声明
|
|
277
310
|
- fix:
|
|
278
|
-
-
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
- 修复 `TaskRedisTransport._transport` 中使用 `id()` 来计算task_id导致的问题
|
|
283
|
-
- 修复部分任务无法被hash导致的panic问题
|
|
311
|
+
- i18n本地化在部分字段上失效的问题
|
|
312
|
+
- 直接点击仪表盘中错误数字跳转到错误日志页后, 设置面板显示的还是仪表盘页面的设置
|
|
313
|
+
- 前端中为各项仪表盘请求添加 `RequestSeq`, 以避免前后发送两个请求, 但因为延迟关系, 先发送的请求的返回覆盖掉后发送请求的返回
|
|
314
|
+
- 修复前端中各项空字段需要在第一次refresh才显示的问题, 体感上会导致"加载"很慢
|
|
284
315
|
- chore:
|
|
285
|
-
-
|
|
286
|
-
-
|
|
287
|
-
- 在 `start_*` 函数的doc-string中标注该函数为一次性调用函数
|
|
316
|
+
- 将文档更新翻译为英/日两语
|
|
317
|
+
- 这项操作太耗token了
|
|
288
318
|
|
|
289
319
|
更多过往日志可看:
|
|
290
320
|
|
|
@@ -215,12 +215,12 @@ flowchart TD
|
|
|
215
215
|
|
|
216
216
|
## 环境要求(Requirements)
|
|
217
217
|
|
|
218
|
-
**CelestialFlow** 基于 Python 3.
|
|
218
|
+
**CelestialFlow** 基于 Python 3.12+,并依赖以下核心组件。
|
|
219
219
|
请确保你的环境能够正常安装这些依赖(`pip install celestialflow` 会自动安装)。
|
|
220
220
|
|
|
221
221
|
| 依赖包 | 说明 |
|
|
222
222
|
| ----------------- | ---- |
|
|
223
|
-
| **Python ≥ 3.
|
|
223
|
+
| **Python ≥ 3.12** | 运行环境,建议使用 3.12 及以上版本 |
|
|
224
224
|
| **fastapi** | Web 服务接口框架(用于任务可视化与远程控制) |
|
|
225
225
|
| **uvicorn** | FastAPI 的高性能 ASGI 服务器 |
|
|
226
226
|
| **requests** | HTTP 客户端库,用于任务状态上报与远程调用 |
|
|
@@ -235,31 +235,61 @@ flowchart TD
|
|
|
235
235
|
<p align="center">
|
|
236
236
|
<img src="https://raw.githubusercontent.com/Mr-xiaotian/CelestialFlow/main/img/file_structure.svg" alt="FileStructure" />
|
|
237
237
|
<br/>
|
|
238
|
-
<em>celestial-flow 3.2.
|
|
238
|
+
<em>celestial-flow 3.2.3</em>
|
|
239
239
|
</p>
|
|
240
240
|
|
|
241
241
|
(该视图由我的另一个项目[CelestialVault](https://github.com/Mr-xiaotian/CelestialVault)中inst_file.FileTree.print_tree()生成。转换为图片则借助[Carbon](https://carbon.now.sh)。)
|
|
242
242
|
|
|
243
243
|
## 版本日志(Version Log)
|
|
244
|
-
- 3.2.
|
|
244
|
+
- 3.2.3
|
|
245
245
|
- feat:
|
|
246
|
-
-
|
|
247
|
-
|
|
248
|
-
-
|
|
246
|
+
- **[IMPORTANT]** 前端仪表盘设置面板中新添 `节点等待使用全局估计` 开关, 开启后节点卡片中原 `等待` 量将被替换为 `全局等待`, 并在卡片中显示 `全局剩余时间`
|
|
247
|
+
- 这个功能非常有趣, 开启前后能看到数值大幅波动
|
|
248
|
+
- **[IMPORTANT]** 重写任务注入页面, 现在实用性远远高于之前版本
|
|
249
|
+
- 可以给每个节点单独配置注入任务列表, 在一起发送
|
|
250
|
+
- **[IMPORTANT]** 移除 `TaskExecutor` 中 `get_args` 与 `process_result` 两个方法, 以及 `unpack_task_args` 属性
|
|
251
|
+
- 这是为引入泛型必要的修改
|
|
252
|
+
- `process_result` 功能很简单, 对func输出的result进行再次处理, 但事实上在输入func前对齐进行包装也能达到一样的效果
|
|
253
|
+
- `get_args` 功能更为复杂, 可以直接将前一节点提供的 `result` 转为当前节点所需的 `task` 类型, 非常灵活; 但问题在于太过灵活, 导致使用心智负担很大
|
|
254
|
+
- `unpack_task_args` 就是 `get_args` 带来的一项心智负担, 默认 `get_args` 会把 `task` 进行 `(task, )` 包裹后发送给func, 开启 `unpack_task_args` 后则直接发送
|
|
255
|
+
- **[IMPORTANT]** `graph` 的init参数中添加 `name`, 以与 `executor` `stage` 一致
|
|
256
|
+
- 破坏接口破坏性更新
|
|
257
|
+
- 在日志的 `start_graph` `end_graph` 与web端的 `graph_anaylysis` 中都有显示
|
|
258
|
+
- 彻底移除前后端通信中的 `graph_summary` , 原本残余的 `全局剩余时间` 现在拆为各个节点的 `全局等待` 与 `全局剩余时间`
|
|
259
|
+
- 这里所说的 `全局` 意为根据图论关系, 由上游剩余的任务数估算下游总共能获得多少任务
|
|
260
|
+
- 例如: 图关系 `A -> B`, A已处理任务2, 未处理任务3, B已处理任务4, 未处理任务2. 这意味着A成功的2个任务为B带来总共了6个任务, 那么我们可以据此估计B总功能获取"3/2*6=9"个任务, 因此B的 `等待` 任务数量为2, 但 `全局等待` 任务数量为5
|
|
261
|
+
- 前端中添加部分提示气泡, 鼠标放上去后可以介绍相关信息, 例如本次新加入的节点 `全局等待` 的含义
|
|
262
|
+
- 移除前端中节点卡片的拖拽功能
|
|
263
|
+
- 这个功能是在最早加入web页面时添加的, 当时感觉很帅, 但现在有点玩腻了
|
|
264
|
+
- 前端错误日志页面添加 `任务注入` 按钮, 可以把选定任务直接添加到任务注入页面中节点的代注入任务列表中
|
|
265
|
+
- 在 `TaskSplitter` 中添加 `split_item` 方法, 可自由定义
|
|
266
|
+
- 原本的 `splitter` 非常依赖于 `get_args`, 现在通过 `split_item` 方法稍微弥补其缺失的灵活性
|
|
249
267
|
- refactor:
|
|
250
|
-
-
|
|
251
|
-
|
|
268
|
+
- **[IMPORTANT]** 引入泛型, 同时强制性要求py版本>=3.12
|
|
269
|
+
- 泛型的引入使得代码更加类型安全, 同时也提高了代码的可读性
|
|
270
|
+
- 3.12版本对泛型的表述非常直观
|
|
271
|
+
- 移除前端代码中所有对 `localStorage` 的使用
|
|
272
|
+
- 在已经有config配置文件的情况下意义不大, 反而会带来困扰
|
|
273
|
+
- 将任务队列的drain操作从graph层移至stage层
|
|
274
|
+
- 之前不能这样做是因为节点的 `stage_mode` 可能为 `process`, 此时在主进程持有的节点非真实运行的节点
|
|
275
|
+
- 算是3.2.0版本带来的持久影响之一
|
|
276
|
+
- 优化 `TaskMetric` 中对锁的使用
|
|
277
|
+
- 移除 `TaskEnvelope` 中的 `change_id()` 方法, 现在默认envelope不可变, 同时 `emit_retry_envelope` 中不再把原有的envelope的id修改后继续提交给worker, 而是直接使用新生成的envelope
|
|
278
|
+
- 移除错误日志中的 `error` `error_repr` `task_repr` 字段
|
|
279
|
+
- 修改前后端通信中任务注入数据的格式, 以方便同时提交多个节点的任务数据
|
|
280
|
+
- 前端代码中开启strict检查
|
|
281
|
+
- 将前端中 `injection.css` 文件拆分成多个文件
|
|
282
|
+
- 修改 `config.json` 的数据格式, 现在按照生效区域进行分类
|
|
283
|
+
- 收紧前端中的数据类型
|
|
284
|
+
- 添加 `ReportTaskGraph` 类型, 专门用于给reporter做类型声明
|
|
252
285
|
- fix:
|
|
253
|
-
-
|
|
254
|
-
-
|
|
255
|
-
-
|
|
256
|
-
-
|
|
257
|
-
- 修复 `TaskRedisTransport._transport` 中使用 `id()` 来计算task_id导致的问题
|
|
258
|
-
- 修复部分任务无法被hash导致的panic问题
|
|
286
|
+
- i18n本地化在部分字段上失效的问题
|
|
287
|
+
- 直接点击仪表盘中错误数字跳转到错误日志页后, 设置面板显示的还是仪表盘页面的设置
|
|
288
|
+
- 前端中为各项仪表盘请求添加 `RequestSeq`, 以避免前后发送两个请求, 但因为延迟关系, 先发送的请求的返回覆盖掉后发送请求的返回
|
|
289
|
+
- 修复前端中各项空字段需要在第一次refresh才显示的问题, 体感上会导致"加载"很慢
|
|
259
290
|
- chore:
|
|
260
|
-
-
|
|
261
|
-
-
|
|
262
|
-
- 在 `start_*` 函数的doc-string中标注该函数为一次性调用函数
|
|
291
|
+
- 将文档更新翻译为英/日两语
|
|
292
|
+
- 这项操作太耗token了
|
|
263
293
|
|
|
264
294
|
更多过往日志可看:
|
|
265
295
|
|
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "celestialflow"
|
|
7
|
-
version = "3.2.
|
|
7
|
+
version = "3.2.3"
|
|
8
8
|
description = "A flexible GRAPH-based task orchestration framework."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
11
|
authors = [{ name = "Mr-xiaotian", email = "mingxiaomingtian@gmail.com" }]
|
|
12
12
|
keywords = ["workflow", "task", "graph", "async", "CelestialFlow"]
|
|
13
|
-
requires-python = ">=3.
|
|
13
|
+
requires-python = ">=3.12"
|
|
14
14
|
|
|
15
15
|
dependencies = [
|
|
16
16
|
"tqdm",
|
|
@@ -20,7 +20,7 @@ dependencies = [
|
|
|
20
20
|
"networkx",
|
|
21
21
|
"redis",
|
|
22
22
|
"jinja2",
|
|
23
|
-
"celestialtree>=0.1.
|
|
23
|
+
"celestialtree>=0.1.3",
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
classifiers = [
|
|
@@ -79,14 +79,11 @@ include = ["src"]
|
|
|
79
79
|
ignore = ["tests", "**/tests/**", "typings", "demo", "bench", "experiments", "examples", "temp"]
|
|
80
80
|
|
|
81
81
|
typeCheckingMode = "strict"
|
|
82
|
-
reportExplicitAny = "none"
|
|
83
|
-
reportAny = "none"
|
|
84
|
-
reportUnannotatedClassAttribute = "none"
|
|
85
82
|
reportUnusedFunction = "none"
|
|
86
83
|
reportImplicitOverride = "none"
|
|
87
84
|
|
|
88
85
|
[tool.ruff]
|
|
89
|
-
target-version = "
|
|
86
|
+
target-version = "py312"
|
|
90
87
|
exclude = ["tests", "typings", "demo", "bench", "experiments", "examples", "temp"]
|
|
91
88
|
|
|
92
89
|
[tool.ruff.lint]
|
|
@@ -20,24 +20,21 @@ from ..observability import NullTaskReporter, TaskReporter
|
|
|
20
20
|
from ..persistence import FailInlet, FailSpout, LogInlet, LogSpout
|
|
21
21
|
from ..persistence.util_jsonl import load_task_by_error, load_task_by_stage
|
|
22
22
|
from ..runtime import TaskInQueue, TaskOutQueue
|
|
23
|
+
from ..runtime.util_constant import LEVEL_DICT, STAGE_STYLE
|
|
23
24
|
from ..runtime.util_errors import (
|
|
24
25
|
CelestialTreeConnectionError,
|
|
25
26
|
DuplicateNodeError,
|
|
27
|
+
LogLevelError,
|
|
26
28
|
RuntimeStateError,
|
|
27
29
|
ScheduleModeError,
|
|
28
|
-
UnconsumedError,
|
|
29
30
|
)
|
|
30
31
|
from ..runtime.util_estimators import (
|
|
31
32
|
calc_elapsed,
|
|
32
|
-
|
|
33
|
+
calc_global_pending,
|
|
33
34
|
calc_remaining,
|
|
34
35
|
)
|
|
35
|
-
from ..runtime.util_types import
|
|
36
|
-
|
|
37
|
-
CTreeEvent,
|
|
38
|
-
TerminationSignal,
|
|
39
|
-
)
|
|
40
|
-
from ..stage import TaskStage
|
|
36
|
+
from ..runtime.util_types import TerminationSignal
|
|
37
|
+
from ..stage.util_types import AnyTaskStage
|
|
41
38
|
from ..utils.util_collections import cluster_by_value_sorted
|
|
42
39
|
from ..utils.util_format import format_avg_time
|
|
43
40
|
from .util_analysis import (
|
|
@@ -62,6 +59,7 @@ class TaskGraph:
|
|
|
62
59
|
|
|
63
60
|
def __init__(
|
|
64
61
|
self,
|
|
62
|
+
name: str,
|
|
65
63
|
schedule_mode: str = "eager",
|
|
66
64
|
log_level: str = "INFO",
|
|
67
65
|
) -> None:
|
|
@@ -77,6 +75,7 @@ class TaskGraph:
|
|
|
77
75
|
- 完成一次 start_graph() 后,不应复用同一实例再次启动。
|
|
78
76
|
- 如需重复执行,请重新构建新的 TaskGraph 与节点对象。
|
|
79
77
|
|
|
78
|
+
:param name: 任务图名称
|
|
80
79
|
:param schedule_mode: str, optional, default = 'eager'
|
|
81
80
|
控制任务图的调度布局模式,支持以下两种策略:
|
|
82
81
|
- 'eager':
|
|
@@ -97,6 +96,7 @@ class TaskGraph:
|
|
|
97
96
|
- 'ERROR'
|
|
98
97
|
- 'CRITICAL'
|
|
99
98
|
"""
|
|
99
|
+
self._set_name(name)
|
|
100
100
|
self._set_log_level(log_level)
|
|
101
101
|
self._set_schedule_mode(schedule_mode)
|
|
102
102
|
self.set_reporter()
|
|
@@ -119,7 +119,7 @@ class TaskGraph:
|
|
|
119
119
|
# 用于保存所有子线程的引用
|
|
120
120
|
self.threads: list[threading.Thread] = []
|
|
121
121
|
# 用于保存每个节点的运行信息
|
|
122
|
-
self.stage_dict: dict[str,
|
|
122
|
+
self.stage_dict: dict[str, AnyTaskStage] = {}
|
|
123
123
|
# 用于保存每个节点的上一次collect_runtime_snapshot()的状态信息
|
|
124
124
|
self.status_dict: dict[str, dict[str, Any]] = defaultdict(dict)
|
|
125
125
|
# 用于保存最近一次状态快照对应的统一时间戳
|
|
@@ -127,10 +127,12 @@ class TaskGraph:
|
|
|
127
127
|
# 用于保存每个节点的输入任务ID集合
|
|
128
128
|
self.input_ids: dict[str, set[int]] = defaultdict(set)
|
|
129
129
|
# 用于保存源节点列表(由 _build_analysis 自动计算)
|
|
130
|
-
self.source_stages: list[
|
|
130
|
+
self.source_stages: list[AnyTaskStage] = []
|
|
131
131
|
# 用于保存图结构的邻接表
|
|
132
132
|
self.out_edges: dict[str, list[str]] = defaultdict(list)
|
|
133
133
|
self.in_edges: dict[str, list[str]] = defaultdict(list)
|
|
134
|
+
# 用于保存任务图启动时间
|
|
135
|
+
self.start_time: float = 0.0
|
|
134
136
|
|
|
135
137
|
def _init_spout(self) -> None:
|
|
136
138
|
"""
|
|
@@ -148,7 +150,7 @@ class TaskGraph:
|
|
|
148
150
|
|
|
149
151
|
# ==== 建图 ====
|
|
150
152
|
|
|
151
|
-
def set_stages(self, stages: list[
|
|
153
|
+
def set_stages(self, stages: list[AnyTaskStage]) -> None:
|
|
152
154
|
"""
|
|
153
155
|
添加节点到任务图中
|
|
154
156
|
|
|
@@ -167,7 +169,11 @@ class TaskGraph:
|
|
|
167
169
|
|
|
168
170
|
stage.set_inlet(fail_queue, log_queue)
|
|
169
171
|
|
|
170
|
-
def connect(
|
|
172
|
+
def connect(
|
|
173
|
+
self,
|
|
174
|
+
from_stages: list[AnyTaskStage],
|
|
175
|
+
to_stages: list[AnyTaskStage],
|
|
176
|
+
) -> None:
|
|
171
177
|
"""
|
|
172
178
|
建立超边连接:from_stages 中的每个节点连接到 to_stages 中的每个节点。
|
|
173
179
|
|
|
@@ -181,6 +187,14 @@ class TaskGraph:
|
|
|
181
187
|
|
|
182
188
|
# ==== 配置 ====
|
|
183
189
|
|
|
190
|
+
def _set_name(self, name: str) -> None:
|
|
191
|
+
"""
|
|
192
|
+
设置任务图名称
|
|
193
|
+
|
|
194
|
+
:param name: 任务图名称
|
|
195
|
+
"""
|
|
196
|
+
self.name = name
|
|
197
|
+
|
|
184
198
|
def _set_schedule_mode(self, schedule_mode: str) -> None:
|
|
185
199
|
"""
|
|
186
200
|
设置任务链的执行模式
|
|
@@ -202,6 +216,8 @@ class TaskGraph:
|
|
|
202
216
|
:param level: 日志级别, 默认为 "INFO"
|
|
203
217
|
"""
|
|
204
218
|
self.log_level = level.upper()
|
|
219
|
+
if self.log_level not in LEVEL_DICT:
|
|
220
|
+
raise LogLevelError(self.log_level)
|
|
205
221
|
|
|
206
222
|
def set_reporter(
|
|
207
223
|
self, is_report: bool = False, host: str = "127.0.0.1", port: int = 5000
|
|
@@ -283,15 +299,15 @@ class TaskGraph:
|
|
|
283
299
|
if not self.in_edges[stage_name]: # 如果没有前驱
|
|
284
300
|
continue
|
|
285
301
|
|
|
286
|
-
in_queue: TaskInQueue = current_stage.task_queue
|
|
287
|
-
prev_stages: list[
|
|
302
|
+
in_queue: TaskInQueue[Any] = current_stage.task_queue
|
|
303
|
+
prev_stages: list[AnyTaskStage] = []
|
|
288
304
|
|
|
289
305
|
# 遍历每个前驱,创建边队列
|
|
290
306
|
for prev_stage_name in self.in_edges[stage_name]:
|
|
291
307
|
in_queue.add_source_name(prev_stage_name)
|
|
292
308
|
|
|
293
309
|
prev_stage = self.stage_dict[prev_stage_name]
|
|
294
|
-
prev_out_queue: TaskOutQueue = prev_stage.result_queue
|
|
310
|
+
prev_out_queue: TaskOutQueue[Any] = prev_stage.result_queue
|
|
295
311
|
prev_out_queue.add_queue(in_queue.queue, stage_name)
|
|
296
312
|
prev_stages.append(prev_stage)
|
|
297
313
|
|
|
@@ -328,7 +344,7 @@ class TaskGraph:
|
|
|
328
344
|
for name, tasks in tasks_dict.items():
|
|
329
345
|
if name not in self.stage_dict:
|
|
330
346
|
continue
|
|
331
|
-
stage:
|
|
347
|
+
stage: AnyTaskStage = self.stage_dict[name]
|
|
332
348
|
|
|
333
349
|
for task in tasks:
|
|
334
350
|
if isinstance(task, TerminationSignal):
|
|
@@ -374,13 +390,14 @@ class TaskGraph:
|
|
|
374
390
|
RuntimeWarning,
|
|
375
391
|
stacklevel=2,
|
|
376
392
|
)
|
|
377
|
-
|
|
393
|
+
_start = time.perf_counter()
|
|
394
|
+
self.start_time = time.time()
|
|
378
395
|
|
|
379
396
|
try:
|
|
380
397
|
self.fail_spout.start()
|
|
381
398
|
self.log_spout.start()
|
|
382
|
-
self.log_inlet.start_graph(self.get_structure_list())
|
|
383
|
-
self.fail_inlet.start_graph(self.get_structure_graph())
|
|
399
|
+
self.log_inlet.start_graph(self.name, self.get_structure_list())
|
|
400
|
+
self.fail_inlet.start_graph(self.name, self.get_structure_graph())
|
|
384
401
|
self.reporter.start()
|
|
385
402
|
|
|
386
403
|
self.put_stage_queue(init_tasks_dict, put_termination_signal)
|
|
@@ -390,7 +407,7 @@ class TaskGraph:
|
|
|
390
407
|
self._finalize_nodes()
|
|
391
408
|
|
|
392
409
|
self.reporter.stop()
|
|
393
|
-
self.log_inlet.end_graph(time.perf_counter() -
|
|
410
|
+
self.log_inlet.end_graph(self.name, time.perf_counter() - _start)
|
|
394
411
|
self.fail_spout.stop()
|
|
395
412
|
self.log_spout.stop()
|
|
396
413
|
|
|
@@ -413,7 +430,7 @@ class TaskGraph:
|
|
|
413
430
|
|
|
414
431
|
threads: list[threading.Thread] = []
|
|
415
432
|
for stage_name in layer:
|
|
416
|
-
stage:
|
|
433
|
+
stage: AnyTaskStage = self.stage_dict[stage_name]
|
|
417
434
|
self._execute_stage(stage)
|
|
418
435
|
if stage.stage_mode == "thread":
|
|
419
436
|
threads.append(self.threads[-1])
|
|
@@ -424,7 +441,7 @@ class TaskGraph:
|
|
|
424
441
|
|
|
425
442
|
self.log_inlet.end_layer(layer, time.perf_counter() - start_time)
|
|
426
443
|
|
|
427
|
-
def _execute_stage(self, stage:
|
|
444
|
+
def _execute_stage(self, stage: AnyTaskStage) -> None:
|
|
428
445
|
"""
|
|
429
446
|
执行单个节点
|
|
430
447
|
|
|
@@ -474,33 +491,8 @@ class TaskGraph:
|
|
|
474
491
|
stage.mark_stopped()
|
|
475
492
|
|
|
476
493
|
# 收集并持久化每个 stage 中未消费的任务
|
|
477
|
-
for
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
remaining_sources = in_queue.drain()
|
|
481
|
-
stage.metrics.add_error_count(len(remaining_sources))
|
|
482
|
-
|
|
483
|
-
# 持久化逻辑
|
|
484
|
-
for source in remaining_sources:
|
|
485
|
-
task: Any = source.task
|
|
486
|
-
task_id: int = source.id
|
|
487
|
-
error_id: int = self.ctree_client.emit(
|
|
488
|
-
CTreeEvent.TASK_ERROR,
|
|
489
|
-
[task_id],
|
|
490
|
-
payload=stage.get_summary(),
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
self.fail_inlet.task_error(
|
|
494
|
-
stage_name, error_id, UnconsumedError(), task
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
self.log_inlet.task_error(
|
|
498
|
-
stage.get_func_name(),
|
|
499
|
-
stage.get_task_repr(task),
|
|
500
|
-
UnconsumedError(),
|
|
501
|
-
task_id,
|
|
502
|
-
error_id,
|
|
503
|
-
)
|
|
494
|
+
for stage in self.stage_dict.values():
|
|
495
|
+
stage.drain_task_queue()
|
|
504
496
|
|
|
505
497
|
self.collect_runtime_snapshot()
|
|
506
498
|
|
|
@@ -508,10 +500,10 @@ class TaskGraph:
|
|
|
508
500
|
|
|
509
501
|
def _snapshot_one_stage(
|
|
510
502
|
self,
|
|
511
|
-
stage:
|
|
503
|
+
stage: AnyTaskStage,
|
|
512
504
|
last_status: dict[str, Any],
|
|
513
505
|
interval: float,
|
|
514
|
-
) -> tuple[dict[str, Any], tuple[int, int
|
|
506
|
+
) -> tuple[dict[str, Any], tuple[int, int]]:
|
|
515
507
|
"""
|
|
516
508
|
计算单个 stage 的运行时快照
|
|
517
509
|
:param stage: 节点实例
|
|
@@ -547,37 +539,30 @@ class TaskGraph:
|
|
|
547
539
|
|
|
548
540
|
processed = int(stage_counts["tasks_processed"] or 0)
|
|
549
541
|
pending = int(stage_counts["tasks_pending"] or 0)
|
|
550
|
-
elapsed_f = float(elapsed or 0.0)
|
|
551
|
-
remaining_f = float(remaining or 0.0)
|
|
552
542
|
|
|
553
|
-
return snapshot, (processed, pending
|
|
543
|
+
return snapshot, (processed, pending)
|
|
554
544
|
|
|
555
|
-
def
|
|
545
|
+
def _calc_graph_pending(
|
|
556
546
|
self,
|
|
557
547
|
running_processed_map: dict[str, int],
|
|
558
548
|
running_pending_map: dict[str, int],
|
|
559
|
-
|
|
560
|
-
running_remaining_map: dict[str, float],
|
|
561
|
-
) -> dict[str, float]:
|
|
549
|
+
) -> dict[str, int]:
|
|
562
550
|
"""
|
|
563
|
-
根据 DAG/非 DAG
|
|
551
|
+
根据 DAG/非 DAG 策略计算全局预计待处理任务数量
|
|
564
552
|
|
|
565
553
|
:param running_processed_map: 各节点已处理任务数
|
|
566
554
|
:param running_pending_map: 各节点待处理任务数
|
|
567
|
-
:
|
|
568
|
-
:param running_remaining_map: 各节点预计剩余时间
|
|
569
|
-
:return: 全局预计剩余时间(秒)
|
|
555
|
+
:return: 全局预计待处理任务数量
|
|
570
556
|
"""
|
|
571
557
|
if not self.is_dag:
|
|
572
|
-
return
|
|
558
|
+
return running_pending_map
|
|
573
559
|
|
|
574
|
-
|
|
560
|
+
total_pending_map = calc_global_pending(
|
|
575
561
|
self.networkx_graph,
|
|
576
562
|
running_processed_map,
|
|
577
563
|
running_pending_map,
|
|
578
|
-
running_elapsed_map,
|
|
579
564
|
)
|
|
580
|
-
return
|
|
565
|
+
return total_pending_map
|
|
581
566
|
|
|
582
567
|
def collect_runtime_snapshot(self) -> None:
|
|
583
568
|
"""
|
|
@@ -587,39 +572,36 @@ class TaskGraph:
|
|
|
587
572
|
now = time.time()
|
|
588
573
|
interval = self.reporter.interval
|
|
589
574
|
|
|
590
|
-
# 为全局预计
|
|
591
|
-
running_elapsed_map: dict[str, float] = {}
|
|
575
|
+
# 为全局预计 tasks_pending 收集数据
|
|
592
576
|
running_processed_map: dict[str, int] = {}
|
|
593
577
|
running_pending_map: dict[str, int] = {}
|
|
594
|
-
running_remaining_map: dict[str, float] = {}
|
|
595
578
|
|
|
596
579
|
for stage_name, stage in self.stage_dict.items():
|
|
597
580
|
last_status = self.status_dict.get(stage_name, {})
|
|
598
581
|
|
|
599
|
-
snapshot, (processed, pending
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
interval,
|
|
604
|
-
)
|
|
582
|
+
snapshot, (processed, pending) = self._snapshot_one_stage(
|
|
583
|
+
stage,
|
|
584
|
+
last_status,
|
|
585
|
+
interval,
|
|
605
586
|
)
|
|
606
587
|
|
|
607
588
|
status_dict[stage_name] = snapshot
|
|
608
589
|
|
|
590
|
+
# 更新各节点的 processed, pending, remaining 数据
|
|
609
591
|
running_processed_map[stage_name] = processed
|
|
610
592
|
running_pending_map[stage_name] = pending
|
|
611
|
-
running_elapsed_map[stage_name] = elapsed
|
|
612
|
-
running_remaining_map[stage_name] = remaining
|
|
613
593
|
|
|
614
|
-
|
|
594
|
+
total_pending_map = self._calc_graph_pending(
|
|
615
595
|
running_processed_map,
|
|
616
596
|
running_pending_map,
|
|
617
|
-
running_elapsed_map,
|
|
618
|
-
running_remaining_map,
|
|
619
597
|
)
|
|
620
|
-
|
|
621
598
|
for stage_name, stage_status in status_dict.items():
|
|
622
|
-
stage_status["
|
|
599
|
+
stage_status["total_tasks_pending"] = total_pending_map[stage_name]
|
|
600
|
+
stage_status["total_remaining_time"] = calc_remaining(
|
|
601
|
+
stage_status["tasks_processed"],
|
|
602
|
+
stage_status["total_tasks_pending"],
|
|
603
|
+
stage_status["elapsed_time"],
|
|
604
|
+
)
|
|
623
605
|
|
|
624
606
|
self.status_dict = status_dict
|
|
625
607
|
self.status_timestamp = now
|
|
@@ -669,12 +651,14 @@ class TaskGraph:
|
|
|
669
651
|
"""
|
|
670
652
|
获取任务图的分析信息
|
|
671
653
|
|
|
672
|
-
:return: 包含 is_dag, schedule_mode, class_name, layers_dict 的字典
|
|
654
|
+
:return: 包含 name, startTime, is_dag, schedule_mode, class_name, layers_dict 的字典
|
|
673
655
|
"""
|
|
674
656
|
return {
|
|
657
|
+
"name": self.name,
|
|
658
|
+
"startTime": self.start_time,
|
|
659
|
+
"className": self.__class__.__name__,
|
|
675
660
|
"isDAG": self.is_dag,
|
|
676
661
|
"scheduleMode": self.schedule_mode,
|
|
677
|
-
"className": self.__class__.__name__,
|
|
678
662
|
"layersDict": self.layers_dict,
|
|
679
663
|
}
|
|
680
664
|
|
|
@@ -728,7 +712,7 @@ class TaskGraph:
|
|
|
728
712
|
return ""
|
|
729
713
|
return format_descendants_forest(descendants, STAGE_STYLE)
|
|
730
714
|
|
|
731
|
-
def get_source_stages(self) -> list[
|
|
715
|
+
def get_source_stages(self) -> list[AnyTaskStage]:
|
|
732
716
|
"""
|
|
733
717
|
获取源节点列表
|
|
734
718
|
|