celestialflow 3.2.1__tar.gz → 3.2.2__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.
Files changed (95) hide show
  1. {celestialflow-3.2.1 → celestialflow-3.2.2}/PKG-INFO +21 -47
  2. {celestialflow-3.2.1 → celestialflow-3.2.2}/README.md +20 -46
  3. {celestialflow-3.2.1 → celestialflow-3.2.2}/pyproject.toml +1 -1
  4. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/graph/core_graph.py +42 -26
  5. celestialflow-3.2.2/src/celestialflow/graph/util_serialize.py +153 -0
  6. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/observability/core_report.py +6 -20
  7. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/persistence/core_fail.py +3 -3
  8. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/core_dispatch.py +10 -17
  9. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/core_envelope.py +10 -1
  10. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/util_estimators.py +3 -3
  11. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/stage/core_executor.py +18 -2
  12. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/stage/core_stage.py +19 -3
  13. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/stage/core_stages.py +11 -7
  14. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/config.json +3 -1
  15. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/core_server.py +83 -11
  16. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/routes/pull_routes.py +16 -25
  17. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/routes/push_routes.py +167 -186
  18. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/base.css +54 -5
  19. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/dashboard_history.js +11 -0
  20. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/dashboard_structure.js +55 -34
  21. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/dashboard_summary.js +2 -23
  22. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/errors.js +22 -3
  23. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/i18n.js +21 -0
  24. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/injection.js +1 -0
  25. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/layout_editor.js +6 -0
  26. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/main.js +70 -14
  27. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/web_config.js +9 -0
  28. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/dashboard_history.ts +12 -0
  29. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/dashboard_statuses.ts +1 -0
  30. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/dashboard_structure.ts +71 -41
  31. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/dashboard_summary.ts +2 -25
  32. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/errors.ts +37 -3
  33. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/i18n.ts +21 -0
  34. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/injection.ts +1 -0
  35. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/layout_editor.ts +6 -0
  36. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/main.ts +79 -17
  37. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/web_config.ts +12 -0
  38. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/templates/index.html +102 -29
  39. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/util_error.py +23 -8
  40. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/util_models.py +3 -7
  41. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow.egg-info/PKG-INFO +21 -47
  42. celestialflow-3.2.1/src/celestialflow/graph/util_serialize.py +0 -151
  43. {celestialflow-3.2.1 → celestialflow-3.2.2}/setup.cfg +0 -0
  44. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/__init__.py +0 -0
  45. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/funnel/__init__.py +0 -0
  46. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/funnel/core_inlet.py +0 -0
  47. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/funnel/core_spout.py +0 -0
  48. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/graph/__init__.py +0 -0
  49. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/graph/core_structure.py +0 -0
  50. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/graph/util_analysis.py +0 -0
  51. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/observability/__init__.py +0 -0
  52. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/observability/core_observer.py +0 -0
  53. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/observability/core_progress.py +0 -0
  54. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/persistence/__init__.py +0 -0
  55. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/persistence/core_log.py +0 -0
  56. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/persistence/core_success.py +0 -0
  57. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/persistence/util_constant.py +0 -0
  58. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/persistence/util_jsonl.py +0 -0
  59. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/__init__.py +0 -0
  60. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/core_metrics.py +0 -0
  61. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/core_queue.py +0 -0
  62. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/util_errors.py +0 -0
  63. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/util_hash.py +0 -0
  64. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/runtime/util_types.py +0 -0
  65. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/stage/__init__.py +0 -0
  66. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/utils/__init__.py +0 -0
  67. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/utils/util_benchmark.py +0 -0
  68. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/utils/util_clone.py +0 -0
  69. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/utils/util_collections.py +0 -0
  70. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/utils/util_format.py +0 -0
  71. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/__init__.py +0 -0
  72. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/routes/__init__.py +0 -0
  73. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/_colors.css +0 -0
  74. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/dashboard.css +0 -0
  75. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/dashboard_analysis.css +0 -0
  76. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/dashboard_history.css +0 -0
  77. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/dashboard_statuses.css +0 -0
  78. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/dashboard_structure.css +0 -0
  79. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/dashboard_summary.css +0 -0
  80. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/errors.css +0 -0
  81. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/css/injection.css +0 -0
  82. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/favicon.ico +0 -0
  83. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/dashboard_analysis.js +0 -0
  84. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/dashboard_statuses.js +0 -0
  85. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/js/utils.js +0 -0
  86. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/dashboard_analysis.ts +0 -0
  87. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/globals.d.ts +0 -0
  88. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/static/ts/utils.ts +0 -0
  89. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/util_cal.py +0 -0
  90. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow/web/util_config.py +0 -0
  91. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow.egg-info/SOURCES.txt +0 -0
  92. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow.egg-info/dependency_links.txt +0 -0
  93. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow.egg-info/entry_points.txt +0 -0
  94. {celestialflow-3.2.1 → celestialflow-3.2.2}/src/celestialflow.egg-info/requires.txt +0 -0
  95. {celestialflow-3.2.1 → celestialflow-3.2.2}/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.1
3
+ Version: 3.2.2
4
4
  Summary: A flexible GRAPH-based task orchestration framework.
5
5
  Author-email: Mr-xiaotian <mingxiaomingtian@gmail.com>
6
6
  License: MIT
@@ -212,7 +212,7 @@ flowchart TD
212
212
 
213
213
  以下三篇可以作为补充阅读:
214
214
 
215
- - [runtime/util_queue.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_queue.md)
215
+ - [runtime/util_hash.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_hash.md)
216
216
  - [runtime/util_types.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_types.md)
217
217
  - [runtime/util_errors.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_errors.md)
218
218
  - [persistence/core_fail.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/persistence/core_fail.md)
@@ -228,15 +228,15 @@ flowchart TD
228
228
 
229
229
  你可以继续运行更多的演示代码,这里记录了各个演示文件与其中的演示函数说明:
230
230
 
231
- [🎮demo/](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/demo/)
231
+ [🎮demo/](https://github.com/Mr-xiaotian/CelestialFlow/tree/main/docs/zh-CN/demo)
232
232
 
233
233
  ​如果你想运行测试代码, 可以先查看如下文档内容:
234
234
 
235
- [🧪tests/](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/tests/)
235
+ [🧪tests/](https://github.com/Mr-xiaotian/CelestialFlow/tree/main/docs/zh-CN/tests)
236
236
 
237
237
  如果你想查看bench内容, 这里的数据成为框架中部分设计的决策依据:
238
238
 
239
- [⚡bench/](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/bench/)
239
+ [⚡bench/](https://github.com/Mr-xiaotian/CelestialFlow/tree/main/docs/zh-CN/bench)
240
240
 
241
241
  ## 环境要求(Requirements)
242
242
 
@@ -260,57 +260,31 @@ 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.1</em>
263
+ <em>celestial-flow 3.2.2</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.1:
269
+ - 3.2.2
270
270
  - feat:
271
- - **[Important]** 大幅强化配置按钮功能
272
- - 现在可以配置界面语言,并支持中、日、英三语言切换
273
- - 可以配置错误日志每页日志条数
274
- - 可以配置结构图中是否显示增量,不过现在样式上有点丑
275
- - 以及最重要的,可以直接编辑仪表盘页的卡片布局
276
- - 另外,所有设置保存成功后会有提示
277
- - 折线图中可以选择数据类型
278
- - 现在包括"数据累计"、"等待队列"和"数据变化率"
279
- - 对 structure 的一些调整
280
- - 所有 structure 的参数中添加 `stage_mode`,用于统一控制节点模式
281
- - 对 struct 中节点不再重新命名
282
- - 在部分 Spout 中增加缓冲机制
271
+ - `core_server` 中添加数据锁, 避免并发访问导致的错误状态
272
+ - 优化前端设置面板的显示, 现在只显示全局设置与当前页相关设置
273
+ - 在设置面板中添加全局设置中的 "是否自动更新" 选项与错误日志页面中的 "排序方式" 两项
283
274
  - refactor:
284
- - **[Important]** 删除 executor 中的 `tag` 属性,并全面使用 `name` 属性进行替代
285
- - `tag` 的出现是为了适应早期无法区分节点而设计的,但现在 `name` 已经强制唯一性,继续使用冗长的 `tag` 会导致不便
286
- - **[Important]** 将 executor 中 `task_queue` 与 `result_queue` 的定义提前到 `__init__` 中
287
- - 对于 executor 来说区别不大,但对于 stage 而言这是更理想且优雅的形式,只是由于原先 `stage_mode="process"` 时不允许执行函数内带有 `MPQueue`,所以才使用 graph 中统一定义,然后通过 process 的 args 注入的形式
288
- - **[Important]** 重构 `core_server`,将其分解出 `routes/` 与 `util_models`,实现结构优化
289
- - 进一步地,将 `log_queue` 和 `fail_queue` 的注入也提前到 `graph.set_stages` 中,实现 `stage.start_stage` 完全无输入参数
290
- - 同时在 executor 中添加 `put_task` 与 `put_signal`,并在 graph 中进行复用
291
- - 之前不能这样做是因为 stage 中此时还没有定义 queue
292
- - 移除 `core_graph` 中的 `StageRuntime`
293
- - 将类型标注中的部分 `Any` 改为更明确的类型
294
- - 删除 HTML 中的仪表盘部分的 card,现在交给 `web-config` 来定义
295
- - 删除部分没必要的前后端通信,优化通信负载
296
- - 移除后端传递的节点历史信息,由前端进行维护
297
- - 移除总体统计中除"总剩余时间"的后端数据,由前端进行计算
298
- - 优化错误存储的 JSONL 数据结构,现在保存更细致的错误信息
299
- - 调整 pyright 规则,并实现 pyright 0 error / 0 warning
300
- - 给 `web/` 下几乎所有 `.ts` 与 `.css` 文件重命名,并整理文件内容边界
301
- - `util_error` 中添加更多错误类型,保证项目中所有主动 raise 的错误都在当前的错误体系下
302
- - 删除前端代码中所有的 `onclick`,改用 `data-*` 属性
303
- - 清简 `config.json` 中的部分字段
304
- - 删除部分不必要的代码
275
+ - 删除前后端通讯中的 `summary` , 节点的总体预期结束时间由各个节点的 `status` 分别传递, 并由前端计算整体的预期结束时间
276
+ - 修改 `structure_graph`(原 `structure_json`) 字段的内容, 现在更为简洁, 避免信息冗余, 同时方便后续拓展
305
277
  - fix:
306
- - 对部分太宽泛的错误捕捉进行收窄
278
+ - 修复指标折线图中指标选择失效的问题
279
+ - 修改 `report.stop` 中_refresh_all的执行顺序, 避免与thread中的刷新冲突
280
+ - 在 `graph._finalize_nodes` 中添加对thread未终止的防御性检查
281
+ - 修复 `stage` 中 `start_time` 在未定义前被 `report` 调用的问题
282
+ - 修复 `TaskRedisTransport._transport` 中使用 `id()` 来计算task_id导致的问题
283
+ - 修复部分任务无法被hash导致的panic问题
307
284
  - chore:
308
- - 添加更多测试代码,并整理 `tests/` 结构
309
- - 修复 `bench/` 中的一些问题
310
- - 主要是 `bench_execution_mode` 中的两种 Fibonacci 运算量级不同,无法正常进行模型 bench
311
- - 添加 `.github/workflows`,实现 CI/CD
312
- - 更新支持的 Python 版本为 3.11,以与部分库要求相符
313
- - 添加两个 skill,分别用于更新文档与审查项目
285
+ - 删除所有的 `type: ignore`
286
+ - 好看不少
287
+ - `start_*` 函数的doc-string中标注该函数为一次性调用函数
314
288
 
315
289
  更多过往日志可看:
316
290
 
@@ -187,7 +187,7 @@ flowchart TD
187
187
 
188
188
  以下三篇可以作为补充阅读:
189
189
 
190
- - [runtime/util_queue.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_queue.md)
190
+ - [runtime/util_hash.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_hash.md)
191
191
  - [runtime/util_types.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_types.md)
192
192
  - [runtime/util_errors.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/runtime/util_errors.md)
193
193
  - [persistence/core_fail.md](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/src/persistence/core_fail.md)
@@ -203,15 +203,15 @@ flowchart TD
203
203
 
204
204
  你可以继续运行更多的演示代码,这里记录了各个演示文件与其中的演示函数说明:
205
205
 
206
- [🎮demo/](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/demo/)
206
+ [🎮demo/](https://github.com/Mr-xiaotian/CelestialFlow/tree/main/docs/zh-CN/demo)
207
207
 
208
208
  ​如果你想运行测试代码, 可以先查看如下文档内容:
209
209
 
210
- [🧪tests/](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/tests/)
210
+ [🧪tests/](https://github.com/Mr-xiaotian/CelestialFlow/tree/main/docs/zh-CN/tests)
211
211
 
212
212
  如果你想查看bench内容, 这里的数据成为框架中部分设计的决策依据:
213
213
 
214
- [⚡bench/](https://github.com/Mr-xiaotian/CelestialFlow/blob/main/docs/zh-CN/bench/)
214
+ [⚡bench/](https://github.com/Mr-xiaotian/CelestialFlow/tree/main/docs/zh-CN/bench)
215
215
 
216
216
  ## 环境要求(Requirements)
217
217
 
@@ -235,57 +235,31 @@ 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.1</em>
238
+ <em>celestial-flow 3.2.2</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.1:
244
+ - 3.2.2
245
245
  - feat:
246
- - **[Important]** 大幅强化配置按钮功能
247
- - 现在可以配置界面语言,并支持中、日、英三语言切换
248
- - 可以配置错误日志每页日志条数
249
- - 可以配置结构图中是否显示增量,不过现在样式上有点丑
250
- - 以及最重要的,可以直接编辑仪表盘页的卡片布局
251
- - 另外,所有设置保存成功后会有提示
252
- - 折线图中可以选择数据类型
253
- - 现在包括"数据累计"、"等待队列"和"数据变化率"
254
- - 对 structure 的一些调整
255
- - 所有 structure 的参数中添加 `stage_mode`,用于统一控制节点模式
256
- - 对 struct 中节点不再重新命名
257
- - 在部分 Spout 中增加缓冲机制
246
+ - `core_server` 中添加数据锁, 避免并发访问导致的错误状态
247
+ - 优化前端设置面板的显示, 现在只显示全局设置与当前页相关设置
248
+ - 在设置面板中添加全局设置中的 "是否自动更新" 选项与错误日志页面中的 "排序方式" 两项
258
249
  - refactor:
259
- - **[Important]** 删除 executor 中的 `tag` 属性,并全面使用 `name` 属性进行替代
260
- - `tag` 的出现是为了适应早期无法区分节点而设计的,但现在 `name` 已经强制唯一性,继续使用冗长的 `tag` 会导致不便
261
- - **[Important]** 将 executor 中 `task_queue` 与 `result_queue` 的定义提前到 `__init__` 中
262
- - 对于 executor 来说区别不大,但对于 stage 而言这是更理想且优雅的形式,只是由于原先 `stage_mode="process"` 时不允许执行函数内带有 `MPQueue`,所以才使用 graph 中统一定义,然后通过 process 的 args 注入的形式
263
- - **[Important]** 重构 `core_server`,将其分解出 `routes/` 与 `util_models`,实现结构优化
264
- - 进一步地,将 `log_queue` 和 `fail_queue` 的注入也提前到 `graph.set_stages` 中,实现 `stage.start_stage` 完全无输入参数
265
- - 同时在 executor 中添加 `put_task` 与 `put_signal`,并在 graph 中进行复用
266
- - 之前不能这样做是因为 stage 中此时还没有定义 queue
267
- - 移除 `core_graph` 中的 `StageRuntime`
268
- - 将类型标注中的部分 `Any` 改为更明确的类型
269
- - 删除 HTML 中的仪表盘部分的 card,现在交给 `web-config` 来定义
270
- - 删除部分没必要的前后端通信,优化通信负载
271
- - 移除后端传递的节点历史信息,由前端进行维护
272
- - 移除总体统计中除"总剩余时间"的后端数据,由前端进行计算
273
- - 优化错误存储的 JSONL 数据结构,现在保存更细致的错误信息
274
- - 调整 pyright 规则,并实现 pyright 0 error / 0 warning
275
- - 给 `web/` 下几乎所有 `.ts` 与 `.css` 文件重命名,并整理文件内容边界
276
- - `util_error` 中添加更多错误类型,保证项目中所有主动 raise 的错误都在当前的错误体系下
277
- - 删除前端代码中所有的 `onclick`,改用 `data-*` 属性
278
- - 清简 `config.json` 中的部分字段
279
- - 删除部分不必要的代码
250
+ - 删除前后端通讯中的 `summary` , 节点的总体预期结束时间由各个节点的 `status` 分别传递, 并由前端计算整体的预期结束时间
251
+ - 修改 `structure_graph`(原 `structure_json`) 字段的内容, 现在更为简洁, 避免信息冗余, 同时方便后续拓展
280
252
  - fix:
281
- - 对部分太宽泛的错误捕捉进行收窄
253
+ - 修复指标折线图中指标选择失效的问题
254
+ - 修改 `report.stop` 中_refresh_all的执行顺序, 避免与thread中的刷新冲突
255
+ - 在 `graph._finalize_nodes` 中添加对thread未终止的防御性检查
256
+ - 修复 `stage` 中 `start_time` 在未定义前被 `report` 调用的问题
257
+ - 修复 `TaskRedisTransport._transport` 中使用 `id()` 来计算task_id导致的问题
258
+ - 修复部分任务无法被hash导致的panic问题
282
259
  - chore:
283
- - 添加更多测试代码,并整理 `tests/` 结构
284
- - 修复 `bench/` 中的一些问题
285
- - 主要是 `bench_execution_mode` 中的两种 Fibonacci 运算量级不同,无法正常进行模型 bench
286
- - 添加 `.github/workflows`,实现 CI/CD
287
- - 更新支持的 Python 版本为 3.11,以与部分库要求相符
288
- - 添加两个 skill,分别用于更新文档与审查项目
260
+ - 删除所有的 `type: ignore`
261
+ - 好看不少
262
+ - `start_*` 函数的doc-string中标注该函数为一次性调用函数
289
263
 
290
264
  更多过往日志可看:
291
265
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "celestialflow"
7
- version = "3.2.1"
7
+ version = "3.2.2"
8
8
  description = "A flexible GRAPH-based task orchestration framework."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -23,6 +23,7 @@ from ..runtime import TaskInQueue, TaskOutQueue
23
23
  from ..runtime.util_errors import (
24
24
  CelestialTreeConnectionError,
25
25
  DuplicateNodeError,
26
+ RuntimeStateError,
26
27
  ScheduleModeError,
27
28
  UnconsumedError,
28
29
  )
@@ -48,7 +49,14 @@ from .util_serialize import build_structure_graph, format_structure_list_from_gr
48
49
 
49
50
 
50
51
  class TaskGraph:
51
- """任务图核心类,负责构建、连接和调度一组 TaskStage 节点。"""
52
+ """任务图核心类,负责构建、连接和调度一组 TaskStage 节点。
53
+
54
+ 注意:
55
+ - TaskGraph 是一次性对象,设计上只应启动一次。
56
+ - start_graph() 执行后,内部会建立并持有运行期资源、队列绑定和线程状态,
57
+ 不保证可被安全重置或重复启动。
58
+ - 如需再次运行相同流程,请重新创建 TaskGraph 实例及其关联的 TaskStage。
59
+ """
52
60
 
53
61
  # ==== 初始化 ====
54
62
 
@@ -64,6 +72,11 @@ class TaskGraph:
64
72
  分层等多种形式的任务执行流程。通过分析图结构和调度布局策略,实现灵活的
65
73
  DAG 任务调度控制。
66
74
 
75
+ 生命周期说明:
76
+ - 当前 TaskGraph 实例为一次性对象。
77
+ - 完成一次 start_graph() 后,不应复用同一实例再次启动。
78
+ - 如需重复执行,请重新构建新的 TaskGraph 与节点对象。
79
+
67
80
  :param schedule_mode: str, optional, default = 'eager'
68
81
  控制任务图的调度布局模式,支持以下两种策略:
69
82
  - 'eager':
@@ -111,8 +124,6 @@ class TaskGraph:
111
124
  self.status_dict: dict[str, dict[str, Any]] = defaultdict(dict)
112
125
  # 用于保存最近一次状态快照对应的统一时间戳
113
126
  self.status_timestamp: float = 0.0
114
- # 用于保存任务图的摘要信息
115
- self.graph_summary: dict[str, int | float] = {}
116
127
  # 用于保存每个节点的输入任务ID集合
117
128
  self.input_ids: dict[str, set[int]] = defaultdict(set)
118
129
  # 用于保存源节点列表(由 _build_analysis 自动计算)
@@ -294,8 +305,8 @@ class TaskGraph:
294
305
  source_names = find_source_nodes(self.networkx_graph)
295
306
  self.source_stages = [self.stage_dict[name] for name in source_names]
296
307
 
297
- self.structure_json = build_structure_graph(
298
- self.source_stages, self.out_edges, self.stage_dict
308
+ self.structure_graph = build_structure_graph(
309
+ self.stage_dict, self.out_edges, self.source_stages
299
310
  )
300
311
 
301
312
  self.is_dag = is_directed_acyclic_graph(self.networkx_graph)
@@ -343,6 +354,9 @@ class TaskGraph:
343
354
 
344
355
  :param init_tasks_dict: 任务列表
345
356
  :param put_termination_signal: 是否注入终止信号,默认 True
357
+ :note:
358
+ TaskGraph 为一次性对象;当前实例启动并运行完成后,不保证可安全再次调用
359
+ start_graph()。如需重复执行,请创建新的 TaskGraph 实例。
346
360
  """
347
361
  self._build_resources()
348
362
  self._build_analysis()
@@ -366,7 +380,7 @@ class TaskGraph:
366
380
  self.fail_spout.start()
367
381
  self.log_spout.start()
368
382
  self.log_inlet.start_graph(self.get_structure_list())
369
- self.fail_inlet.start_graph(self.get_structure_json())
383
+ self.fail_inlet.start_graph(self.get_structure_graph())
370
384
  self.reporter.start()
371
385
 
372
386
  self.put_stage_queue(init_tasks_dict, put_termination_signal)
@@ -442,8 +456,18 @@ class TaskGraph:
442
456
  确保所有线程安全结束,更新节点状态,并导出每个节点队列剩余任务。
443
457
  """
444
458
  # 确保所有线程安全结束(线程不可 terminate,仅做 cooperative join)
459
+ alive_thread_names: list[str] = []
445
460
  for t in self.threads:
446
461
  t.join(timeout=10)
462
+ if t.is_alive():
463
+ alive_thread_names.append(t.name)
464
+
465
+ if alive_thread_names:
466
+ stage_names = ", ".join(sorted(alive_thread_names))
467
+ raise RuntimeStateError(
468
+ "TaskGraph shutdown incomplete; alive stage threads remain after finalize: "
469
+ f"{stage_names}"
470
+ )
447
471
 
448
472
  # 更新所有节点状态为"已停止"
449
473
  for stage in self.stage_dict.values():
@@ -534,7 +558,7 @@ class TaskGraph:
534
558
  running_pending_map: dict[str, int],
535
559
  running_elapsed_map: dict[str, float],
536
560
  running_remaining_map: dict[str, float],
537
- ) -> float:
561
+ ) -> dict[str, float]:
538
562
  """
539
563
  根据 DAG/非 DAG 策略计算全局预计剩余时间
540
564
 
@@ -545,15 +569,15 @@ class TaskGraph:
545
569
  :return: 全局预计剩余时间(秒)
546
570
  """
547
571
  if not self.is_dag:
548
- return max(running_remaining_map.values(), default=0.0)
572
+ return running_remaining_map
549
573
 
550
- expected_pending_map = calc_global_remain_equal_pred(
574
+ total_remaining_map = calc_global_remain_equal_pred(
551
575
  self.networkx_graph,
552
576
  running_processed_map,
553
577
  running_pending_map,
554
578
  running_elapsed_map,
555
579
  )
556
- return max(expected_pending_map.values(), default=0.0)
580
+ return total_remaining_map
557
581
 
558
582
  def collect_runtime_snapshot(self) -> None:
559
583
  """
@@ -563,8 +587,6 @@ class TaskGraph:
563
587
  now = time.time()
564
588
  interval = self.reporter.interval
565
589
 
566
- totals = {"total_remain": 0.0}
567
-
568
590
  # 为全局预计 remaining 收集
569
591
  running_elapsed_map: dict[str, float] = {}
570
592
  running_processed_map: dict[str, int] = {}
@@ -589,16 +611,18 @@ class TaskGraph:
589
611
  running_elapsed_map[stage_name] = elapsed
590
612
  running_remaining_map[stage_name] = remaining
591
613
 
592
- totals["total_remain"] = self._calc_graph_remain(
614
+ total_remaining_map = self._calc_graph_remain(
593
615
  running_processed_map,
594
616
  running_pending_map,
595
617
  running_elapsed_map,
596
618
  running_remaining_map,
597
619
  )
598
620
 
621
+ for stage_name, stage_status in status_dict.items():
622
+ stage_status["total_remaining_time"] = total_remaining_map[stage_name]
623
+
599
624
  self.status_dict = status_dict
600
625
  self.status_timestamp = now
601
- self.graph_summary = dict(totals)
602
626
 
603
627
  # ==== 查询接口 ====
604
628
 
@@ -641,14 +665,6 @@ class TaskGraph:
641
665
  "status": self.status_dict,
642
666
  }
643
667
 
644
- def get_graph_summary(self) -> dict[str, int | float]:
645
- """
646
- 获取任务链的摘要信息字典
647
-
648
- :return: 当前仅包含 total_remain 的字典
649
- """
650
- return self.graph_summary
651
-
652
668
  def get_graph_analysis(self) -> dict[str, Any]:
653
669
  """
654
670
  获取任务图的分析信息
@@ -662,13 +678,13 @@ class TaskGraph:
662
678
  "layersDict": self.layers_dict,
663
679
  }
664
680
 
665
- def get_structure_json(self) -> list[dict[str, Any]]:
681
+ def get_structure_graph(self) -> dict[str, Any]:
666
682
  """
667
683
  获取任务图的 JSON 结构
668
684
 
669
- :return: JSON 格式的任务图结构列表
685
+ :return: JSON 格式的任务图结构字典
670
686
  """
671
- return self.structure_json
687
+ return self.structure_graph
672
688
 
673
689
  def get_structure_list(self) -> list[str]:
674
690
  """
@@ -676,7 +692,7 @@ class TaskGraph:
676
692
 
677
693
  :return: 带边框的格式化字符串列表
678
694
  """
679
- return format_structure_list_from_graph(self.structure_json)
695
+ return format_structure_list_from_graph(self.structure_graph)
680
696
 
681
697
  def get_networkx_graph(self) -> DiGraph[Any]:
682
698
  """
@@ -0,0 +1,153 @@
1
+ # graph/util_serialize.py
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ from ..stage import TaskStage
8
+
9
+
10
+ # ======== 处理图结构 ========
11
+ def build_structure_graph(
12
+ stage_dict: dict[str, TaskStage],
13
+ out_edges: dict[str, list[str]],
14
+ source_stages: list[TaskStage],
15
+ ) -> dict[str, Any]:
16
+ """
17
+ 从源节点、邻接表和节点字典构建标准化图结构。
18
+
19
+ 返回的结构采用 ``nodes + edges + source_nodes`` 形式:
20
+ - ``nodes``: 以节点名为 key 的节点元信息字典
21
+ - ``edges``: 邻接表 {stage_name: [next_stage_name, ...]}
22
+ - ``source_nodes``: 图入口节点名称列表
23
+
24
+ :param stage_dict: {stage_name: TaskStage}
25
+ :param out_edges: 邻接表 {stage_name: [next_stage_name, ...]}
26
+ :param source_stages: 源节点列表
27
+ :return: 标准化图结构字典
28
+ """
29
+ nodes: dict[str, dict[str, Any]] = {}
30
+ edges: dict[str, list[str]] = {}
31
+
32
+ for stage_name, stage in stage_dict.items():
33
+ node_summary = dict(stage.get_summary())
34
+ node_summary.pop("name", None)
35
+ nodes[stage_name] = node_summary
36
+ edges[stage_name] = list(out_edges.get(stage_name, []))
37
+
38
+ return {
39
+ "nodes": nodes,
40
+ "edges": edges,
41
+ "source_nodes": [stage.get_name() for stage in source_stages],
42
+ }
43
+
44
+
45
+ def format_structure_list_from_graph(
46
+ structure: dict[str, Any] | None = None,
47
+ ) -> list[str]:
48
+ """
49
+ 从标准化图结构生成格式化任务结构文本列表(带边框)。
50
+
51
+ :param structure: ``nodes + edges + source_nodes`` 形式的图结构
52
+ :return: 带边框的格式化字符串列表
53
+ """
54
+
55
+ nodes: dict[str, dict[str, Any]] = dict((structure or {}).get("nodes", {}) or {})
56
+ edges: dict[str, list[str]] = dict((structure or {}).get("edges", {}) or {})
57
+ source_nodes: list[str] = list((structure or {}).get("source_nodes", []) or [])
58
+
59
+ if not nodes:
60
+ return ["+ No stages defined +"]
61
+
62
+ if not source_nodes:
63
+ child_names = {child for child_list in edges.values() for child in child_list}
64
+ source_nodes = [name for name in nodes if name not in child_names]
65
+ if not source_nodes:
66
+ source_nodes = [next(iter(nodes))]
67
+
68
+ expanded_nodes: set[str] = set()
69
+
70
+ def node_label(node_name: str, *, is_ref: bool = False) -> str:
71
+ """
72
+ 生成节点的显示标签字符串。
73
+
74
+ :param node_name: 节点名称
75
+ :param is_ref: 是否按引用节点展示
76
+ :return: 格式化的标签字符串
77
+ """
78
+ node = nodes.get(node_name, {})
79
+ visited_note = " [Ref]" if is_ref else ""
80
+ F = node.get("func_name", "?") # F
81
+ S = node.get("stage_mode", "?") # S
82
+ E = node.get("execution_mode", "?") # E
83
+ W = node.get("max_workers", "?") # W
84
+
85
+ return f"{node_name}::{F} (S:{S}, E:{E}, W:{W}){visited_note}"
86
+
87
+ # 只渲染"子节点"(有父节点)——保证一定画连接符
88
+ def build_child_lines(
89
+ node_name: str, prefix: str, is_last: bool
90
+ ) -> list[str]:
91
+ """
92
+ 递归构建子节点的树形显示行。
93
+
94
+ :param node_name: 子节点名称
95
+ :param prefix: 当前行的缩进前缀
96
+ :param is_last: 是否为同级最后一个节点
97
+ :return: 格式化的行列表
98
+ """
99
+ connector = "╘-->" if is_last else "╞-->"
100
+ is_ref = node_name in expanded_nodes
101
+ lines = [f"{prefix}{connector}{node_label(node_name, is_ref=is_ref)}"]
102
+ if is_ref:
103
+ return lines
104
+
105
+ expanded_nodes.add(node_name)
106
+
107
+ # 子节点的 prefix 取决于当前节点是不是 last:last -> 空白,否则竖线延续
108
+ child_prefix = prefix + (" " if is_last else "│ ")
109
+ next_stages = edges.get(node_name, []) or []
110
+ for i, child_name in enumerate(next_stages):
111
+ lines.extend(
112
+ build_child_lines(child_name, child_prefix, i == len(next_stages) - 1)
113
+ )
114
+ return lines
115
+
116
+ # 专门处理 root:不画连接符,不产生祖先竖线
117
+ def build_root_lines(root_name: str) -> list[str]:
118
+ """
119
+ 构建根节点及其子树的树形显示行。
120
+
121
+ :param root_name: 根节点名称
122
+ :return: 格式化的行列表
123
+ """
124
+ is_ref = root_name in expanded_nodes
125
+ lines = [node_label(root_name, is_ref=is_ref)]
126
+ if is_ref:
127
+ return lines
128
+
129
+ expanded_nodes.add(root_name)
130
+ next_stages = edges.get(root_name, []) or []
131
+ for i, child_name in enumerate(next_stages):
132
+ lines.extend(build_child_lines(child_name, "", i == len(next_stages) - 1))
133
+ return lines
134
+
135
+ all_lines: list[str] = []
136
+ rendered_roots: list[str] = []
137
+ for root_name in source_nodes:
138
+ if all_lines:
139
+ all_lines.append("") # 根之间留空行
140
+ all_lines.extend(build_root_lines(root_name))
141
+ rendered_roots.append(root_name)
142
+
143
+ for node_name in nodes:
144
+ if node_name in rendered_roots or node_name in expanded_nodes:
145
+ continue
146
+ if all_lines:
147
+ all_lines.append("")
148
+ all_lines.extend(build_root_lines(node_name))
149
+
150
+ max_length = max(len(line) for line in all_lines)
151
+ content_lines = [f"| {line.ljust(max_length)} |" for line in all_lines]
152
+ border = "+" + "-" * (max_length + 2) + "+"
153
+ return [border, *content_lines, border]
@@ -60,11 +60,11 @@ class TaskReporter:
60
60
 
61
61
  def stop(self) -> None:
62
62
  """停止上报器线程"""
63
- self._refresh_all() # 最后一次
64
63
  self._stop_flag.set()
65
64
  if self._thread is not None:
66
65
  self._thread.join(timeout=2)
67
66
  self._thread = None
67
+ self._refresh_all() # 最后一次
68
68
  self._session.close()
69
69
  self.log_inlet.stop_reporter()
70
70
 
@@ -100,7 +100,6 @@ class TaskReporter:
100
100
  self._push_status()
101
101
  self._push_structure()
102
102
  self._push_analysis()
103
- self._push_summary()
104
103
 
105
104
  # ==== 拉取 ====
106
105
  def _pull_interval(self) -> None:
@@ -139,7 +138,7 @@ class TaskReporter:
139
138
  for task in task_datas
140
139
  ]
141
140
  try:
142
- self.task_graph.put_stage_queue( # type: ignore[reportUnknownMemberType]
141
+ self.task_graph.put_stage_queue(
143
142
  {target_stage: task_datas}, put_termination_signal=False
144
143
  )
145
144
  self.log_inlet.inject_tasks_success(target_stage, task_datas)
@@ -231,7 +230,7 @@ class TaskReporter:
231
230
  def _push_status(self) -> None:
232
231
  """推送状态信息"""
233
232
  try:
234
- payload: dict[str, Any] = self.task_graph.get_status_snapshot() # type: ignore[reportUnknownMemberType]
233
+ payload: dict[str, Any] = self.task_graph.get_status_snapshot()
235
234
  _ = self._session.post(
236
235
  f"{self.base_url}/api/push_status",
237
236
  json=payload,
@@ -243,8 +242,8 @@ class TaskReporter:
243
242
  def _push_structure(self) -> None:
244
243
  """推送结构信息"""
245
244
  try:
246
- structure: list[dict[str, Any]] = self.task_graph.get_structure_json() # type: ignore[reportUnknownMemberType]
247
- payload: dict[str, Any] = {"items": structure}
245
+ structure: dict[str, Any] = self.task_graph.get_structure_graph()
246
+ payload: dict[str, Any] = {"structure": structure}
248
247
  _ = self._session.post(
249
248
  f"{self.base_url}/api/push_structure",
250
249
  json=payload,
@@ -256,7 +255,7 @@ class TaskReporter:
256
255
  def _push_analysis(self) -> None:
257
256
  """推送分析信息"""
258
257
  try:
259
- analysis: dict[str, Any] = self.task_graph.get_graph_analysis() # type: ignore[reportUnknownMemberType]
258
+ analysis: dict[str, Any] = self.task_graph.get_graph_analysis()
260
259
  payload: dict[str, Any] = {"analysis": analysis}
261
260
  _ = self._session.post(
262
261
  f"{self.base_url}/api/push_analysis",
@@ -266,19 +265,6 @@ class TaskReporter:
266
265
  except Exception as e:
267
266
  self.log_inlet.push_analysis_failed(e)
268
267
 
269
- def _push_summary(self) -> None:
270
- """推送摘要信息"""
271
- try:
272
- summary: dict[str, Any] = self.task_graph.get_graph_summary() # type: ignore[reportUnknownMemberType]
273
- payload: dict[str, Any] = {"summary": summary}
274
- _ = self._session.post(
275
- f"{self.base_url}/api/push_summary",
276
- json=payload,
277
- timeout=self._push_timeout(),
278
- )
279
- except Exception as e:
280
- self.log_inlet.push_summary_failed(e)
281
-
282
268
 
283
269
  class NullTaskReporter:
284
270
  """空实现的任务上报器,用于关闭上报功能时的占位对象。"""
@@ -103,15 +103,15 @@ class FailInlet(BaseInlet):
103
103
  """
104
104
  super().__init__(fail_queue)
105
105
 
106
- def start_graph(self, structure_json: list[Any]) -> None:
106
+ def start_graph(self, structure_graph: dict[str, Any]) -> None:
107
107
  """
108
108
  在运行开始时写入任务结构元信息到 jsonl 文件
109
109
 
110
- :param structure_json: 任务图结构 JSON
110
+ :param structure_graph: 任务图结构 JSON
111
111
  """
112
112
  meta_item = {
113
113
  "timestamp": datetime.now().isoformat(),
114
- "structure": structure_json,
114
+ "structure": structure_graph,
115
115
  }
116
116
  self._funnel(meta_item)
117
117