@wubaoqi/guancopilot 0.0.0-stage → 0.2.0
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.
- package/NOTICE.md +17 -0
- package/README.md +146 -2
- package/assets/coreutils.wasm +0 -0
- package/assets/find.wasm +0 -0
- package/assets/guanbi.wasm +4 -0
- package/assets/guancli.wasm +0 -0
- package/assets/guanhelm.wasm +0 -0
- package/assets/jq.wasm +0 -0
- package/assets/openskills.wasm +0 -0
- package/assets/rg.wasm +0 -0
- package/assets/sed.wasm +0 -0
- package/bin/guancopilot +0 -0
- package/bin/guanvm +0 -0
- package/bin/platforms.cjs +6 -0
- package/bin/run.cjs +39 -0
- package/bin/runtime.cjs +44 -0
- package/licenses/Go-LICENSE +27 -0
- package/licenses/browser-_speed-highlight_core-LICENSE +121 -0
- package/licenses/browser-_speed-highlight_core-package.json +14 -0
- package/licenses/browser-dompurify-LICENSE +202 -0
- package/licenses/browser-dompurify-LICENSE-MPL +373 -0
- package/licenses/browser-dompurify-package.json +10 -0
- package/licenses/browser-marked-LICENSE +44 -0
- package/licenses/browser-marked-package.json +10 -0
- package/licenses/coreutils-LICENSE +18 -0
- package/licenses/findutils-LICENSE +18 -0
- package/licenses/github.com_BurntSushi_toml_v1.6.0-COPYING +21 -0
- package/licenses/github.com_dustin_go-humanize_v1.0.1-LICENSE +21 -0
- package/licenses/github.com_google_jsonschema-go_v0.4.3-LICENSE +21 -0
- package/licenses/github.com_google_uuid_v1.6.0-LICENSE +27 -0
- package/licenses/github.com_jackc_pgpassfile_v1.0.0-LICENSE +22 -0
- package/licenses/github.com_jackc_pgservicefile_v0.0.0-20240606120523-5a60cdf6a761-LICENSE +22 -0
- package/licenses/github.com_jackc_pgx_v5_v5.11.0-LICENSE +22 -0
- package/licenses/github.com_jackc_puddle_v2_v2.2.2-LICENSE +22 -0
- package/licenses/github.com_mattn_go-isatty_v0.0.20-LICENSE +9 -0
- package/licenses/github.com_modelcontextprotocol_go-sdk_v1.8.0-LICENSE +216 -0
- package/licenses/github.com_ncruces_go-strftime_v1.0.0-LICENSE +21 -0
- package/licenses/github.com_remyoudompheng_bigfft_v0.0.0-20230129092748-24d4a6f8daec-LICENSE +27 -0
- package/licenses/github.com_santhosh-tekuri_jsonschema_v6_v6.0.3-LICENSE +175 -0
- package/licenses/github.com_segmentio_asm_v1.1.3-LICENSE +21 -0
- package/licenses/github.com_segmentio_encoding_v0.5.4-LICENSE +21 -0
- package/licenses/github.com_tetratelabs_wazero_v1.12.0-LICENSE +201 -0
- package/licenses/github.com_tetratelabs_wazero_v1.12.0-NOTICE +2 -0
- package/licenses/github.com_yosida95_uritemplate_v3_v3.0.2-LICENSE +25 -0
- package/licenses/golang.org_x_image_v0.44.0-LICENSE +27 -0
- package/licenses/golang.org_x_net_v0.58.0-LICENSE +27 -0
- package/licenses/golang.org_x_oauth2_v0.36.0-LICENSE +27 -0
- package/licenses/golang.org_x_sync_v0.22.0-LICENSE +27 -0
- package/licenses/golang.org_x_sys_v0.47.0-LICENSE +27 -0
- package/licenses/golang.org_x_text_v0.41.0-LICENSE +27 -0
- package/licenses/golang.org_x_time_v0.15.0-LICENSE +27 -0
- package/licenses/guanbi-skills-LICENSE +133 -0
- package/licenses/guanbi-skills-LICENSE.README.md +28 -0
- package/licenses/guanbi-skills-LICENSE.zh-CN +82 -0
- package/licenses/jq-COPYING +176 -0
- package/licenses/modernc.org_libc_v1.73.4-LICENSE +27 -0
- package/licenses/modernc.org_libc_v1.73.4-LICENSE-3RD-PARTY.md +305 -0
- package/licenses/modernc.org_mathutil_v1.7.1-LICENSE +27 -0
- package/licenses/modernc.org_memory_v1.11.0-LICENSE +27 -0
- package/licenses/modernc.org_memory_v1.11.0-LICENSE-GO +27 -0
- package/licenses/modernc.org_memory_v1.11.0-LICENSE-LOGO +1 -0
- package/licenses/modernc.org_memory_v1.11.0-LICENSE-MMAP-GO +25 -0
- package/licenses/modernc.org_sqlite_v1.53.0-LICENSE +26 -0
- package/licenses/mvdan.cc_sh_v3_v3.13.1-LICENSE +27 -0
- package/licenses/ripgrep-COPYING +3 -0
- package/licenses/ripgrep-LICENSE-MIT +21 -0
- package/licenses/sed-LICENSE +21 -0
- package/manifest.json +972 -0
- package/package.json +30 -4
- package/plugin/guancopilot.js +193 -0
- package/skills-bundle/.guanvm-skills-bundle +0 -0
- package/skills-bundle/_recipes/dashboard/gates/page_check.js +16 -0
- package/skills-bundle/_recipes/dashboard/gates/report_check.js +4 -0
- package/skills-bundle/_recipes/dashboard/knowledge/01.md +1 -0
- package/skills-bundle/_recipes/dashboard/knowledge/02.md +1 -0
- package/skills-bundle/_recipes/dashboard/knowledge/03.md +1 -0
- package/skills-bundle/_recipes/dashboard/knowledge/04.md +1 -0
- package/skills-bundle/_recipes/dashboard/knowledge/05.md +1 -0
- package/skills-bundle/_recipes/dashboard/knowledge/06.md +1 -0
- package/skills-bundle/_recipes/dashboard/template.json +41 -0
- package/skills-bundle/_recipes/etl/gates/etl_live_check.js +10 -0
- package/skills-bundle/_recipes/etl/gates/etl_report_check.js +3 -0
- package/skills-bundle/_recipes/etl/knowledge/01.md +1 -0
- package/skills-bundle/_recipes/etl/knowledge/02.md +9 -0
- package/skills-bundle/_recipes/etl/knowledge/03.md +1 -0
- package/skills-bundle/_recipes/etl/knowledge/04.md +1 -0
- package/skills-bundle/_recipes/etl/knowledge/05.md +1 -0
- package/skills-bundle/_recipes/etl/template.json +39 -0
- package/skills-bundle/_recipes/hints.json +46 -0
- package/skills-bundle/guancli/.commandface.json +155 -0
- package/skills-bundle/guancli/SKILL.md +342 -0
- package/skills-bundle/guancli/evals/evals.json +156 -0
- package/skills-bundle/guancli/evals/fixtures/metric-candidate-empty-search.json +13 -0
- package/skills-bundle/guancli/evals/fixtures/metric-candidate-prior-request.json +13 -0
- package/skills-bundle/guancli/evals/fixtures/metric-consumption-columns.json +46 -0
- package/skills-bundle/guancli/evals/fixtures/metric-consumption-metadata.json +36 -0
- package/skills-bundle/guancli/evals/fixtures/metric-consumption-query.json +18 -0
- package/skills-bundle/guancli/references/analysis-primitives.md +95 -0
- package/skills-bundle/guancli/references/auth-and-config.md +131 -0
- package/skills-bundle/guancli/references/examples/metric-date-in.json +7 -0
- package/skills-bundle/guancli/references/examples/metric-query-rows.py +83 -0
- package/skills-bundle/guancli/references/examples/metric-query.sh +6 -0
- package/skills-bundle/guancli/references/form-chatbi.md +199 -0
- package/skills-bundle/guancli/references/gateway.md +148 -0
- package/skills-bundle/guancli/references/metric-batch-query.md +82 -0
- package/skills-bundle/guancli/references/metric-commands.md +562 -0
- package/skills-bundle/guancli/references/metric-generic-query.md +215 -0
- package/skills-bundle/guancli/references/metric-json-migration.md +18 -0
- package/skills-bundle/guancli/references/metric-query-recipes.md +358 -0
- package/skills-bundle/guancli/references/preview-and-output.md +192 -0
- package/skills-bundle/guancli/references/resource-query.md +101 -0
- package/skills-bundle/guands/SKILL.md +281 -0
- package/skills-bundle/guands/references/calc-fields-boundaries-and-pitfalls.md +160 -0
- package/skills-bundle/guands/references/command-reference.md +267 -0
- package/skills-bundle/guands/references/incremental-and-schedule.md +157 -0
- package/skills-bundle/guands/references/workflows.md +256 -0
- package/skills-bundle/guanetl/SKILL.md +391 -0
- package/skills-bundle/guanetl/evals/evals.json +41 -0
- package/skills-bundle/guanetl/references/ETL_AI_DEVELOP.md +456 -0
- package/skills-bundle/guanmetric/SKILL.md +144 -0
- package/skills-bundle/guanmetric/evals/evals.json +117 -0
- package/skills-bundle/guanmetric/evals/fixtures/atomic-detail-read-model.json +18 -0
- package/skills-bundle/guanmetric/evals/fixtures/confirmed-template-summary.json +12 -0
- package/skills-bundle/guanmetric/evals/fixtures/create-result-unknown-state.json +13 -0
- package/skills-bundle/guanmetric/evals/forward-eval-2026-09-21.json +62 -0
- package/skills-bundle/guanmetric/references/metric-api-contract-examples.json +690 -0
- package/skills-bundle/guanmetric/references/metric-api-contract.schema.json +349 -0
- package/skills-bundle/guanmetric/references/metric-api-contracts.md +436 -0
- package/skills-bundle/guanmetric/references/metric-atomic-mutation.md +238 -0
- package/skills-bundle/guanmetric/references/metric-batch-status.md +71 -0
- package/skills-bundle/guanmetric/references/metric-business-dictionary-api-contract-examples.json +53 -0
- package/skills-bundle/guanmetric/references/metric-business-dictionary-api-contract.schema.json +26 -0
- package/skills-bundle/guanmetric/references/metric-business-dictionary.md +76 -0
- package/skills-bundle/guanmetric/references/metric-common-fields.md +246 -0
- package/skills-bundle/guanmetric/references/metric-composite-mutation.md +165 -0
- package/skills-bundle/guanmetric/references/metric-delete-mutation.md +70 -0
- package/skills-bundle/guanmetric/references/metric-derived-mutation.md +453 -0
- package/skills-bundle/guanmetric/references/metric-excel-template.md +365 -0
- package/skills-bundle/guanmetric/references/metric-expression-rules.md +146 -0
- package/skills-bundle/guanmetric/references/metric-flow-generate-example.json +79 -0
- package/skills-bundle/guanmetric/references/metric-flow-generate.schema.json +93 -0
- package/skills-bundle/guanmetric/references/metric-flow.md +218 -0
- package/skills-bundle/guanmetric/references/metric-hierarchy-api-contract-examples.json +171 -0
- package/skills-bundle/guanmetric/references/metric-hierarchy-api-contract.schema.json +167 -0
- package/skills-bundle/guanmetric/references/metric-hierarchy-api-contracts.md +193 -0
- package/skills-bundle/guanmetric/references/metric-mutation.md +155 -0
- package/skills-bundle/guanmetric/references/metric-public-dimension-api-contract-examples.json +62 -0
- package/skills-bundle/guanmetric/references/metric-public-dimension-api-contract.schema.json +47 -0
- package/skills-bundle/guanmetric/references/metric-public-dimension.md +155 -0
- package/skills-bundle/guanmetric/references/metric-tree-api-contract-examples.json +277 -0
- package/skills-bundle/guanmetric/references/metric-tree-api-contract.schema.json +263 -0
- package/skills-bundle/guanmetric/references/metric-tree-api-contracts.md +53 -0
- package/skills-bundle/guanmetric/references/metric-tree-mutation.md +500 -0
- package/skills-bundle/guanmetric/references/metric-validation-ownership.md +74 -0
- package/skills-bundle/guanvis/SKILL.md +333 -0
- package/skills-bundle/guanvis/evals/china_map/card_01_basic_map.js +13 -0
- package/skills-bundle/guanvis/evals/china_map/card_02_world_map.js +10 -0
- package/skills-bundle/guanvis/evals/china_map/card_03_point_map.js +12 -0
- package/skills-bundle/guanvis/evals/china_map/page.js +10 -0
- package/skills-bundle/guanvis/evals/china_map/schema.js +10 -0
- package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/README.md +30 -0
- package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/card_01_comparative_mvp.js +72 -0
- package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/page.js +6 -0
- package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/schema.js +22 -0
- package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/verify_default_roundtrip.sh +92 -0
- package/skills-bundle/guanvis/evals/complex_report_pro/card_01_monthly.js +63 -0
- package/skills-bundle/guanvis/evals/complex_report_pro/page.js +6 -0
- package/skills-bundle/guanvis/evals/complex_report_pro/schema.js +6 -0
- package/skills-bundle/guanvis/evals/custom_chart_echarts/card_01_bar.js +13 -0
- package/skills-bundle/guanvis/evals/custom_chart_echarts/card_02_pie.js +13 -0
- package/skills-bundle/guanvis/evals/custom_chart_echarts/charts/bar.js +11 -0
- package/skills-bundle/guanvis/evals/custom_chart_echarts/charts/pie.js +15 -0
- package/skills-bundle/guanvis/evals/custom_chart_echarts/page.js +5 -0
- package/skills-bundle/guanvis/evals/custom_chart_echarts/schema.js +9 -0
- package/skills-bundle/guanvis/evals/custom_chart_sdk/card_01_level_nodes.js +19 -0
- package/skills-bundle/guanvis/evals/custom_chart_sdk/charts/level_nodes.css +51 -0
- package/skills-bundle/guanvis/evals/custom_chart_sdk/charts/level_nodes.html +1 -0
- package/skills-bundle/guanvis/evals/custom_chart_sdk/charts/level_nodes.js +28 -0
- package/skills-bundle/guanvis/evals/custom_chart_sdk/page.js +5 -0
- package/skills-bundle/guanvis/evals/custom_chart_sdk/schema.js +7 -0
- package/skills-bundle/guanvis/evals/dynamic_fields/card_01_dynamic_dataset.js +20 -0
- package/skills-bundle/guanvis/evals/dynamic_fields/card_02_dynamic_metric_chart.js +16 -0
- package/skills-bundle/guanvis/evals/dynamic_fields/metrics.js +19 -0
- package/skills-bundle/guanvis/evals/dynamic_fields/page.js +9 -0
- package/skills-bundle/guanvis/evals/dynamic_fields/schema.js +7 -0
- package/skills-bundle/guanvis/evals/dynamic_fields/verify_default_roundtrip.sh +137 -0
- package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/README.md +26 -0
- package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/card_01_percentage_advcalc.js +44 -0
- package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/card_02_scroll_percentage.js +12 -0
- package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/page.js +6 -0
- package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/schema.js +22 -0
- package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/README.md +28 -0
- package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/card_01_rank_advcalc.js +59 -0
- package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/page.js +6 -0
- package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/schema.js +22 -0
- package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/verify_default_roundtrip.sh +135 -0
- package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/README.md +15 -0
- package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/card_01_running_total_advcalc.js +74 -0
- package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/page.js +6 -0
- package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/schema.js +22 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/card_01_revenue_column.js +10 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/card_02_trend_line.js +9 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/card_03_kpi.js +6 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/card_04_pie.js +9 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/card_05_calc_field_test.js +12 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/page.js +11 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/schema.js +14 -0
- package/skills-bundle/guanvis/evals/sales_dashboard/selector_01_region.js +10 -0
- package/skills-bundle/guanvis/evals/split_charts/card_01_column_split.js +10 -0
- package/skills-bundle/guanvis/evals/split_charts/card_02_line_split.js +10 -0
- package/skills-bundle/guanvis/evals/split_charts/card_03_combo_split.js +11 -0
- package/skills-bundle/guanvis/evals/split_charts/page.js +10 -0
- package/skills-bundle/guanvis/evals/split_charts/schema.js +14 -0
- package/skills-bundle/guanvis/evals/tab_layout/card_00_total_revenue.js +6 -0
- package/skills-bundle/guanvis/evals/tab_layout/card_01_revenue.js +10 -0
- package/skills-bundle/guanvis/evals/tab_layout/card_02_trend.js +9 -0
- package/skills-bundle/guanvis/evals/tab_layout/card_03_story.js +11 -0
- package/skills-bundle/guanvis/evals/tab_layout/page.js +23 -0
- package/skills-bundle/guanvis/evals/tab_layout/schema.js +11 -0
- package/skills-bundle/guanvis/evals/tab_layout/selector_01_region.js +8 -0
- package/skills-bundle/guanvis/references/api-reference.md +476 -0
- package/skills-bundle/guanvis/references/builder-reference.md +1676 -0
- package/skills-bundle/guanvis/references/chart-properties.md +2101 -0
- package/skills-bundle/guanvis/references/checkout-editing.md +53 -0
- package/skills-bundle/guanvis/references/complex-report-pro-patterns.md +398 -0
- package/skills-bundle/guanvis/references/dir-and-page-management.md +48 -0
- package/skills-bundle/guanvis/references/metric-chart-reference.md +258 -0
- package/skills-bundle/guanvis/references/publish-and-constraints.md +60 -0
- package/skills-bundle/guanvis/references/selector-reference.md +431 -0
- package/skills-bundle/guanvis/references/tableau-migration.md +73 -0
- package/skills-bundle/guanvis/references/theme.md +123 -0
- package/skills-bundle/guanvis/references/troubleshooting.md +25 -0
- package/skills-bundle/guanvis/references/validation-and-chart-patterns.md +205 -0
- package/skills-bundle/guanwf/SKILL.md +543 -0
- package/skills-bundle/guanwf/references/ETL_AI_DEVELOP.md +456 -0
- package/skills-bundle/guanwf/references/TASK_NODE_CONTRACTS.md +64 -0
- package/skills-bundle/guanwf/references/WORKFLOW_DSL.md +536 -0
- package/skills-bundle/guanwf/references/WORKFLOW_NODES.md +166 -0
- package/skills-bundle/js/SKILL.md +145 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# 工作流 DSL(workflow.go)
|
|
2
|
+
|
|
3
|
+
`guanwf` 用一个 Go 源文件 `workflow.go` 描述整个工作流(ProcessDefinition)的节点 DAG:
|
|
4
|
+
节点类型、依赖关系、执行条件、重试与超时。各节点的具体内容放在 `nodes/<节点ID>/` 下的
|
|
5
|
+
源文件中。`workflow.go` 由 yaegi 解释执行,不需要本地 Go 编译环境。
|
|
6
|
+
|
|
7
|
+
这是 guanwf 唯一的工作目录格式:单数据流工作流就是只含一个 `DataflowNode` 的 workflow.go,
|
|
8
|
+
多节点工作流(多数据流、数据流 + Python、参数赋值等混合 DAG)按同样方式扩展节点列表。
|
|
9
|
+
|
|
10
|
+
服务端顶层 `dataflowJson` 可能残留已无 task 引用的 raw sidecar。可执行性只由 `workflow.go` 对应的
|
|
11
|
+
SUB_PROCESS tasks 决定;`guanwf get/edit/status` 会分别输出 `rawSidecars`、
|
|
12
|
+
`reachableDataflows`、`orphanSidecars`。孤儿默认保留且不参与拓扑,不能用 raw sidecar 数量判断节点仍存在。
|
|
13
|
+
|
|
14
|
+
## 工作目录结构
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
<workdir>/
|
|
18
|
+
workflow.go # 工作流结构事实源;含凭据时 export 自动收紧权限并加入 .gitignore
|
|
19
|
+
nodes/
|
|
20
|
+
<节点ID>/
|
|
21
|
+
etl.go # DATAFLOW/DB_DATAFLOW 节点:guanetl DSL(可附 *.sql、node_*.json)
|
|
22
|
+
script.py # PYTHON 节点:脚本正文
|
|
23
|
+
python.json # PYTHON 节点:服务端字段透传(edit 生成,勿手改)
|
|
24
|
+
task.json # 0600/当前用户 ACL;RAW 透传节点为完整 TaskNode JSON
|
|
25
|
+
script.sh # SHELL 节点脚本
|
|
26
|
+
query.sql # SQL / PARAMETER_ASSIGNMENT 节点 SQL
|
|
27
|
+
body.json/body.txt # HTTP 请求体
|
|
28
|
+
_wf_state.json # 系统状态(mode=workflow),不手改
|
|
29
|
+
_parent_snapshot.json # 脱敏服务端快照,不手改
|
|
30
|
+
_parent_merge_snapshot.json # 0600/当前用户 ACL 的精确合并基线,不手改
|
|
31
|
+
.gitignore # 自动忽略含原始凭据的精确合并基线
|
|
32
|
+
_layout.json # 节点画布坐标(edit 时保留线上坐标),可不存在
|
|
33
|
+
_python_runtime_context.json # Python Runtime 结构化上下文(命令生成,只读)
|
|
34
|
+
_exported_workflow.json # export 派生产物,不手改
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
可编辑事实源:`workflow.go`、`nodes/<id>/etl.go`、`nodes/<id>/*.sql`、`nodes/<id>/script.py`、
|
|
38
|
+
`nodes/<id>/task.json`。其余根目录 JSON 都是系统状态或派生产物。
|
|
39
|
+
|
|
40
|
+
## workflow.go 写法
|
|
41
|
+
|
|
42
|
+
文件必须是 `package main`,导入 `guanwf/wfdsl`,并定义 `DefineWorkflow() Workflow`:
|
|
43
|
+
|
|
44
|
+
```go
|
|
45
|
+
package main
|
|
46
|
+
|
|
47
|
+
import . "guanwf/wfdsl"
|
|
48
|
+
|
|
49
|
+
func DefineWorkflow() Workflow {
|
|
50
|
+
// 数据流节点:actions 写在 nodes/dataflow_1/etl.go
|
|
51
|
+
df := DataflowNode("dataflow_1", "清洗销售数据", DataflowConfig{})
|
|
52
|
+
|
|
53
|
+
// Python 节点:脚本写在 nodes/python_1/script.py
|
|
54
|
+
py := PythonNode("python_1", "汇总分析", PythonConfig{
|
|
55
|
+
InputDatasets: []string{"<输入数据集ID>"},
|
|
56
|
+
Outputs: []PythonOutput{
|
|
57
|
+
{Name: "销售汇总", ParentDirID: "<数据集目录ID>", UpdateMode: UpdateModeOVERWRITE},
|
|
58
|
+
},
|
|
59
|
+
}, After(df)) // 依赖:df 成功后运行
|
|
60
|
+
|
|
61
|
+
return Workflow{
|
|
62
|
+
Name: "销售数据加工",
|
|
63
|
+
Nodes: []*WfNode{df, py},
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 节点构造函数
|
|
69
|
+
|
|
70
|
+
| 函数 | 任务类型 | 节点源文件 |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `DataflowNode(id, name, DataflowConfig, deps...)` | SUB_PROCESS(数据流) | `nodes/<id>/etl.go` |
|
|
73
|
+
| `DBDataflowNode(id, name, DataflowConfig, deps...)` | SUB_PROCESS(DB 数据流,SQL 下推) | `nodes/<id>/etl.go` |
|
|
74
|
+
| `PythonNode(id, name, PythonConfig, deps...)` | SECURE_PYTHON | `nodes/<id>/script.py`(+ `python.json` 透传) |
|
|
75
|
+
| `SubWorkflowNode(id, name, SubWorkflowConfig, deps...)` | SUB_PROCESS(子工作流) | 无(引用已存在的工作流 ID) |
|
|
76
|
+
| `DatasetNode(id, name, DatasetConfig, deps...)` | DATASET | `task.json` passthrough base |
|
|
77
|
+
| `ShellNode(id, name, ShellConfig, deps...)` | SHELL | 仅导入模型;8.2.0 不支持执行 |
|
|
78
|
+
| `HTTPNode(id, name, HTTPConfig, deps...)` | HTTP | `body.json/body.txt` + `task.json` base |
|
|
79
|
+
| `SQLNode(id, name, SQLConfig, deps...)` | SQL | `query.sql` + `task.json` base |
|
|
80
|
+
| `ParameterAssignmentNode(...)` | PARAMETER_ASSIGNMENT | `query.sql` + `task.json` base |
|
|
81
|
+
| `SwitchNode(...)` | SWITCH | `task.json` passthrough base |
|
|
82
|
+
| `LoopNode(...)` | LOOP | 仅导入模型;8.2.0 不支持执行 |
|
|
83
|
+
| `RawTask(id, deps...)` | 任意(透传) | `nodes/<id>/task.json` |
|
|
84
|
+
|
|
85
|
+
- `id`:节点目录名,也是 TaskNode 的 id。同一工作流内唯一,建议用 `python_1`、`dataflow_1`
|
|
86
|
+
这类稳定短名;edit 回读的节点保留线上原 id。
|
|
87
|
+
- `name`:节点显示名。**同一工作流内必须唯一**(后端 preTasks 依赖按名字引用)。
|
|
88
|
+
- `RawTask` 不带 name 参数,名称从 `task.json` 的 `name` 字段读取。用于未知类型或不符合当前
|
|
89
|
+
结构化合约的旧 payload,除依赖外全部透传。
|
|
90
|
+
- `SubWorkflowNode` 用于编排工作流,见下文「编排工作流」一节。
|
|
91
|
+
- 8.2.0 的后端 TaskParameters 注册表不含 SHELL/LOOP,因此 CLI 会在创建、导出或保存时拒绝这两类节点;循环/脚本能力不能作为本版本 POC 的可用能力承诺。
|
|
92
|
+
|
|
93
|
+
### 工作流参数与引用
|
|
94
|
+
|
|
95
|
+
```go
|
|
96
|
+
return Workflow{
|
|
97
|
+
Name: "每日加工",
|
|
98
|
+
Params: []Param{
|
|
99
|
+
StringParam("biz_date", "${yyyy-MM-dd-1}", ParamDesc("业务日期")),
|
|
100
|
+
NumberParam("batch", 1),
|
|
101
|
+
},
|
|
102
|
+
Nodes: []*WfNode{node},
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`ParamRef("biz_date")`、`DynamicParamRef("system.biz")`、
|
|
107
|
+
`DataDrivenParamRef("result")` 和 `BuiltinParamRef("looptimes")` 只生成平台引用表达式,不在本地求值。
|
|
108
|
+
平台持久化类型为 STRING/NUMBER/DATE;BoolParam 兼容 STRING,TimeParam 兼容 DATE。
|
|
109
|
+
需要保留超大整数或高精度十进制文本时使用 `NumberParam("amount", ExactNumber("1.2300000000000000001"))`;
|
|
110
|
+
`edit` 也会为服务端返回的精确 JSON 数值自动生成 `ExactNumber(...)`,避免经过 `int`/`float64` 丢失精度。
|
|
111
|
+
|
|
112
|
+
完整 TaskNode 字段见 `TASK_NODE_CONTRACTS.md`。
|
|
113
|
+
|
|
114
|
+
### 依赖与执行条件
|
|
115
|
+
|
|
116
|
+
```go
|
|
117
|
+
After(n) // n 成功后运行(SUCCESS)
|
|
118
|
+
AfterFailure(n) // n 失败后运行(FAILURE)
|
|
119
|
+
AfterAny(n) // n 结束后运行,无论成败(ALL)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
依赖作为节点构造函数的可变参数传入,可写多个:
|
|
123
|
+
|
|
124
|
+
```go
|
|
125
|
+
merge := DataflowNode("merge", "合并", DataflowConfig{}, After(a), After(b))
|
|
126
|
+
notify := RawTask("notify_fail", AfterFailure(merge))
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
导出时依赖会生成 `preTasks`(按节点名)+ `preTaskScheduleTypes`(带条件)+ `connects`(画布连线)。
|
|
130
|
+
|
|
131
|
+
### DataflowConfig / PythonConfig 公共字段
|
|
132
|
+
|
|
133
|
+
```go
|
|
134
|
+
DataflowConfig{
|
|
135
|
+
Desc: "描述", // 可选
|
|
136
|
+
Retry: RetryConfig{Max: 2, IntervalMinutes: 5}, // 可选,Max=0 不重试
|
|
137
|
+
TimeoutMinutes: 60, // 可选,>0 启用超时告警+失败策略
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`PythonConfig` 同样支持 `Desc` / `Retry` / `TimeoutMinutes`,另有 Python 专属字段见下节。
|
|
142
|
+
|
|
143
|
+
## Python 节点
|
|
144
|
+
|
|
145
|
+
### 先解析目标 Runtime
|
|
146
|
+
|
|
147
|
+
编写 `script.py` 前先读取目标环境的结构化 Runtime 上下文:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
guanwf python-runtime --dir <workdir> --format json
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`pythonRuntime.default` 是环境默认镜像,`pythonRuntime.catalog` 列出可见镜像,`pythonRuntime.selected` 是命令指定或默认选择,
|
|
154
|
+
`pythonRuntime.nodes[]` 是工作区各 Python 节点根据 `PythonConfig.ImageID` 解析出的实际选择。
|
|
155
|
+
兼容性判断以 `runtimeMode` 和嵌套 `runtime.pythonVersion` 为准,并检查 `runtime.pythonVersionSource`。CLI 不输出
|
|
156
|
+
服务端自由文本 `imageDescription`;经过凭证脱敏的 `imageUrl` 仅供排查,禁止从中推断版本。
|
|
157
|
+
CLI 优先调用兼容接口 `/api/python-images/list` 获取逐镜像 `pythonVersion`;该接口不可用时降级调用
|
|
158
|
+
`/api/system-images/list?type=PYTHON`,并从规范字段 `runtimeEnv`(例如 `Python 3.11`)解析版本。
|
|
159
|
+
|
|
160
|
+
兼容约定:旧接口的 `pythonVersion` 或新接口的合法 `runtimeEnv` 均标记为
|
|
161
|
+
`pythonVersionSource: "api_field"`;两者均缺失或 `runtimeEnv` 无法识别时,CLI 返回 Python 3.8,并标记
|
|
162
|
+
`pythonVersionSource: "compatibility_fallback"`。
|
|
163
|
+
|
|
164
|
+
固定 Runtime 标记 `runtimeMode: "FIXED_RUNTIME"`,配置镜像的动态 Pod 标记
|
|
165
|
+
`runtimeMode: "DYNAMIC_POD"`。目录接口不可用或版本字段缺失时,状态与 warning 会明确说明,
|
|
166
|
+
但兼容目标仍保守落到 Python 3.8;这不是探测结果,不得描述为“平台返回 3.8”。
|
|
167
|
+
以 3.8 为兼容目标时,不要使用标准库 `zoneinfo`、内置泛型 `dict[str, ...]` / `list[...]` 或
|
|
168
|
+
`X | None` 联合类型;使用目标环境已验证的时区方案以及 `typing.Dict` / `typing.List` / `typing.Optional`。
|
|
169
|
+
|
|
170
|
+
`guanwf edit` 遇到 Python 节点时会自动返回这段 JSON,并写入工作目录的
|
|
171
|
+
`_python_runtime_context.json`。也可用 `--image-id <id>` 单独解析某个镜像。
|
|
172
|
+
|
|
173
|
+
### PythonConfig
|
|
174
|
+
|
|
175
|
+
```go
|
|
176
|
+
PythonConfig{
|
|
177
|
+
InputDatasets: []string{"dsId1", "dsId2"}, // 输入数据集 ID,顺序对应 input1, input2, ...
|
|
178
|
+
Outputs: []PythonOutput{ // 输出数据集,顺序对应 output1, output2, ...
|
|
179
|
+
{
|
|
180
|
+
SlotID: "", // edit 自动写入稳定 slot id;仅新建 slot 时留空
|
|
181
|
+
Name: "输出数据集名", // 必填,目录内唯一
|
|
182
|
+
DatasetID: "", // 新建时留空;更新已有数据集时填写其 dsId
|
|
183
|
+
ClearDatasetBinding: false, // 显式解除 edit 回读的已有 dsId 绑定
|
|
184
|
+
Created: false, // true 仅表示数据集由当前工作流创建
|
|
185
|
+
ParentDirID: "<数据集目录ID>", // 必填,guancli dir tree 可查
|
|
186
|
+
UpdateMode: UpdateModeOVERWRITE, // UpdateModeOVERWRITE(覆盖)/ UpdateModeAPPEND(追加),默认 OVERWRITE;字面量 "OVERWRITE" 仍可用
|
|
187
|
+
PrimaryKeys: []string{"id"}, // 可选,按主键去重
|
|
188
|
+
Desc: "描述", // 可选
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
ImageID: "", // 可选,自定义 Python 镜像;默认平台镜像
|
|
192
|
+
CPU: 1, // 可选,沙箱 CPU 核数,默认 1
|
|
193
|
+
MemoryGB: 2, // 可选,沙箱内存 GB,默认 2
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
新建输出数据集时不要填写 `DatasetID`:首次运行由 BI 服务端在 `ParentDirID` 下创建并注册。
|
|
198
|
+
只有明确更新已有数据集时才填写该数据集的 dsId。更新其他流程创建的数据集时保持
|
|
199
|
+
`Created: false`;仅当数据集确由当前工作流创建时使用 `Created: true`。`guanwf edit` 会把
|
|
200
|
+
服务端已有 slot id、dsId 和 created 状态回读,后续导出只按 `SlotID` 继承绑定;显示名不会
|
|
201
|
+
作为身份 fallback。手写新输出时可将直接字面量中的 `SlotID` 留空:首次 `guanwf export`
|
|
202
|
+
会分配稳定 ID 并原子写回 `workflow.go`。如果输出由变量、循环或辅助函数动态构造,CLI 无法
|
|
203
|
+
无歧义改写事实源,必须显式填写唯一 `SlotID`,否则 export 会 fail closed。
|
|
204
|
+
因此,在 edit 工作区中仅把 `DatasetID` 改成空字符串不会删除已有绑定;需要让该输出重新由
|
|
205
|
+
服务端创建数据集时,设置 `ClearDatasetBinding: true`,并保持 `DatasetID` 为空、`Created: false`。
|
|
206
|
+
同一输出在服务端 JSON 中可能同时出现顶层 `dsId` 与 `dataSource.dsId`;两者非空时必须
|
|
207
|
+
完全一致,guanwf 会在 edit/export/save 阶段拒绝冲突身份,禁止猜测应更新哪一个数据集。
|
|
208
|
+
save 与 run 还会 fresh 查询每个非空 dsId:对象必须存在且有权限、类型必须是工作流输出数据集、
|
|
209
|
+
目录和输出槽身份必须一致;`Created: true` 时 producer lineage 必须包含当前工作流。
|
|
210
|
+
同一 Python 节点内的输出 `Name` 必须唯一,以避免服务端目录名称与诊断结果歧义;slot 身份只认 `SlotID`。不同 Python 输出 slot 的非空 dsId
|
|
211
|
+
必须全工作流唯一,并在保存或启动实例前检查。fresh `edit`
|
|
212
|
+
遇到 `created=false` 且对象 404 时不会猜测它是首次运行 placeholder;只有现有 workspace lineage
|
|
213
|
+
或本次明确新增 slot 能证明 placeholder 来源,否则按失效显式绑定 fail closed。
|
|
214
|
+
|
|
215
|
+
### script.py 沙箱约定
|
|
216
|
+
|
|
217
|
+
脚本运行在平台 Python 沙箱容器中(默认镜像带 pandas),沙箱注入了数据集读写函数:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
import pandas as pd
|
|
221
|
+
|
|
222
|
+
df = load_input1() # 读第 1 个输入数据集(InputDatasets[0]),返回 pandas DataFrame
|
|
223
|
+
df2 = load_input2() # 读第 2 个输入(如有)
|
|
224
|
+
|
|
225
|
+
result = df.groupby("大类", as_index=False).agg(总数量=("数量合计", "sum"))
|
|
226
|
+
|
|
227
|
+
save_output1(result) # 写第 1 个输出数据集(Outputs[0]),DataFrame 的列即数据集字段
|
|
228
|
+
print("rows:", len(result)) # print 输出会出现在任务日志里,可用于排查
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
约定:
|
|
232
|
+
|
|
233
|
+
- `load_inputN()` / `save_outputN(df)` 的序号 N 与 `PythonConfig` 中数组顺序一一对应(从 1 开始)。
|
|
234
|
+
- 输出数据集的字段 schema 由首次运行时 `save_outputN` 写出的 DataFrame 推断,不需要预先声明。
|
|
235
|
+
- 每个客户环境的 Python 版本和库可能不同,**生成脚本后先用单节点试运行验证**(见下节),
|
|
236
|
+
不要假设任意第三方库可用;默认镜像保证 pandas 可用。
|
|
237
|
+
- 禁止用硬编码 `/tmp/...` 在节点之间交换文件。跨节点必须走输出/输入数据集;节点内部需要临时
|
|
238
|
+
文件时用 `tempfile.TemporaryDirectory()`,确保任务唯一并自动清理。export 会静态拒绝固定 `/tmp` 字面量。
|
|
239
|
+
|
|
240
|
+
### python.json 透传
|
|
241
|
+
|
|
242
|
+
`guanwf edit` 回读 Python 节点时会生成 `nodes/<id>/python.json`,内容是服务端 TaskNode 中
|
|
243
|
+
除脚本正文之外的完整参数(含服务端生成的 dsId、fieldMappings、k8sConfig 等)。导出时以它为
|
|
244
|
+
基底,`PythonConfig` 中显式设置的字段覆盖其上,脚本正文始终来自 `script.py`。
|
|
245
|
+
|
|
246
|
+
这个透传基底还负责保留输出槽位 id、目录名称/路径及当前 DSL 尚未结构化的服务端字段。因此,
|
|
247
|
+
不修改 `workflow.go` 与 `script.py` 的 edit → export 往返会保持 Python 输出绑定语义不变。
|
|
248
|
+
删除输出 slot 时 CLI 同步删除对应 pending/explicit provenance,后续复用相同 slot id 不会继承旧占位符身份。
|
|
249
|
+
实例定义快照中的 output dsId 仅是身份形状,不是本次运行已完成注册的证据;精确回写和 `run --wait`
|
|
250
|
+
只会在当前实例运行结果给出同 task/slot/dsId 的成功状态或匹配 fresh 实体的 commit token 时提升绑定来源;
|
|
251
|
+
运行结果已给出显式失败终态时,即使 token 匹配也必须失败。
|
|
252
|
+
|
|
253
|
+
不要手改 `python.json`。要改输入/输出/资源配置,改 `workflow.go` 的 `PythonConfig`。
|
|
254
|
+
|
|
255
|
+
## Python 脚本环境校验(run --validate)
|
|
256
|
+
|
|
257
|
+
平台没有 Python 的静态校验接口。**校验脚本的默认方法是 `--validate` 模式**,它完整执行
|
|
258
|
+
脚本但不创建真实输出数据集:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
guanwf export --dir <workdir> # 1. 导出验证 DSL
|
|
262
|
+
guanwf save-draft --dir <workdir> --confirm # 2. 保存草稿(不影响已发布版本)
|
|
263
|
+
guanwf run --dir <workdir> --node "<节点名>" --validate --confirm # 3. 校验运行
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
`--validate` 的工作机制:
|
|
267
|
+
|
|
268
|
+
1. 工作流必须已有草稿;临时定义会清空目标 Python 节点的 `outputDatasets` 注册配置,并给
|
|
269
|
+
节点脚本头部注入 stub,把 `save_outputN` 替换为
|
|
270
|
+
`print(df.dtypes)` + `print(df.head(20))` 并执行真实 PyArrow/Parquet 序列化的实现
|
|
271
|
+
(BI 服务端把真实 `save_outputN`
|
|
272
|
+
定义在用户脚本之前,用户脚本中的重定义会覆盖它)
|
|
273
|
+
2. 单节点试运行草稿(TASK_ONLY + DRAFT),等待完成并拉取日志
|
|
274
|
+
3. stub 在任务唯一临时目录写入 `data.parquet` 验证真实 serializer,随后立即清理;临时定义
|
|
275
|
+
没有输出注册配置,因此服务端跳过输出数据集注册——**不创建、不导入任何真实数据集**
|
|
276
|
+
4. 运行结束后自动把原始草稿(无 stub)重新保存回服务端
|
|
277
|
+
|
|
278
|
+
校验日志中能看到(`--- 脚本输出 (DETAIL) ---` 段):
|
|
279
|
+
|
|
280
|
+
- 脚本所有 `print` 输出和 Python 异常栈
|
|
281
|
+
- `[VALIDATE] save_outputN called: rows=..., cols=...`
|
|
282
|
+
- `[VALIDATE] outputN dtypes:` 输出 DataFrame 的字段类型(即未来数据集的 schema 预览)
|
|
283
|
+
- `[VALIDATE] outputN head(20):` 样例数据
|
|
284
|
+
- `[VALIDATE] outputN serializer=SUCCESS schema=...` 真实 Parquet serializer 校验成功及 schema
|
|
285
|
+
|
|
286
|
+
AI 应根据 dtypes/head 检查输出 schema 是否符合预期,确认后用 `save` 发布并正式
|
|
287
|
+
`run`(正式运行才会真实创建输出数据集)。
|
|
288
|
+
|
|
289
|
+
如果校验中途断掉导致草稿仍带 stub,重新执行 `guanwf save-draft --confirm` 即可恢复(命令结束时
|
|
290
|
+
会有显式警告)。
|
|
291
|
+
|
|
292
|
+
`--validate` 必须搭配 `--node`(节点**显示名**不是 id),且线上工作流必须已有草稿,隐含
|
|
293
|
+
`--draft --wait --logs`。发布态工作流先执行 `save-draft --confirm`;8.2.0 没有废弃临时草稿
|
|
294
|
+
接口,CLI 会在任何线上写入前拒绝直接校验纯发布态,避免校验后残留草稿。
|
|
295
|
+
不带 `--validate` 的 `run --node --draft --wait --logs` 是真实单节点运行,**会创建
|
|
296
|
+
输出数据集**,仅在确认要产出数据时使用。
|
|
297
|
+
|
|
298
|
+
试运行失败时,根据日志区分:脚本语法/库缺失问题改 `script.py`;输入输出配置问题改
|
|
299
|
+
`workflow.go`;平台/环境错误须排查环境。validate 实例若出现输出数据集注册失败,优先确认
|
|
300
|
+
所用 CLI 是否已清空临时定义的输出注册配置,不要改本地源文件硬绕。
|
|
301
|
+
|
|
302
|
+
## 编排工作流(子工作流节点)
|
|
303
|
+
|
|
304
|
+
把一批已存在的作业工作流(每个作业产出数据集)按依赖串成一个主工作流统一调度。
|
|
305
|
+
每个 `SubWorkflowNode` 引用一个已发布的作业工作流;主工作流运行时按依赖顺序触发
|
|
306
|
+
各作业的子实例,任一作业失败则主实例失败(下游不再执行)。
|
|
307
|
+
|
|
308
|
+
```go
|
|
309
|
+
func DefineWorkflow() Workflow {
|
|
310
|
+
// id 直接用被引用的工作流 ID,name 用作业名(同一工作流内唯一)
|
|
311
|
+
a := SubWorkflowNode("<工作流ID_A>", "作业A", SubWorkflowConfig{WorkflowID: "<工作流ID_A>"})
|
|
312
|
+
// data-dep: 销售明细 (dsId...) ← 依赖边注释标明依据
|
|
313
|
+
b := SubWorkflowNode("<工作流ID_B>", "作业B", SubWorkflowConfig{WorkflowID: "<工作流ID_B>"},
|
|
314
|
+
After(a))
|
|
315
|
+
|
|
316
|
+
return Workflow{
|
|
317
|
+
Name: "统一调度主流程",
|
|
318
|
+
Nodes: []*WfNode{a, b},
|
|
319
|
+
// 跨批次依赖声明:消费方刻意读生产方上一批(T-1)产物,不加执行顺序边
|
|
320
|
+
CrossBatch: []CrossBatchDep{
|
|
321
|
+
{Consumer: "作业B", Dataset: "<dsId>", Reason: "读上月快照"},
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
约束(export 校验):
|
|
328
|
+
|
|
329
|
+
- `SubWorkflowConfig.WorkflowID` 必填;同一编排中同一个工作流只能被一个节点引用。
|
|
330
|
+
- 不允许引用编排自身(自引用);嵌套编排如果形成运行时循环,`deps verify` 报 NESTED_CYCLE。
|
|
331
|
+
- `CrossBatch` 声明按 `Consumer`(节点显示名)+ `Dataset`(dsId)匹配,用于把
|
|
332
|
+
verify 的 MISSING_EDGE 降级为 INFO——表示"读旧数据"是刻意设计而不是漏了依赖边。
|
|
333
|
+
|
|
334
|
+
### 依赖从哪里来:血缘,不是口头描述
|
|
335
|
+
|
|
336
|
+
编排的依赖边应来自平台血缘(作业定义中的输入/输出数据集),用 `deps` 子命令自动推导
|
|
337
|
+
和对账,不要凭文档/Excel 手写依赖:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# 1) 从血缘自动生成编排草稿(推荐入口)
|
|
341
|
+
guanwf create --name "统一调度" --type ORCHESTRATION --parent-dir <dirId> --dir <workdir>
|
|
342
|
+
guanwf deps plan --search "<作业名模式>" --yes --dir <workdir> # 按名字搜索作业
|
|
343
|
+
guanwf deps plan --jobs <id1>,<id2>,... --dir <workdir> # 或显式指定工作流 ID
|
|
344
|
+
guanwf deps plan ... --hints hints.json # 附加人工提示
|
|
345
|
+
guanwf deps plan ... --force # 覆盖已有非骨架 workflow.go
|
|
346
|
+
|
|
347
|
+
# 2) 人工微调 workflow.go 后对账
|
|
348
|
+
guanwf export --dir <workdir>
|
|
349
|
+
guanwf deps verify --dir <workdir> # ERROR 必须修复;exit 1 表示有 ERROR
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
`deps plan` 输出的 `workflow.go` 中每条 `After` 边带注释:`data-dep: <数据集>`(血缘推导)
|
|
353
|
+
或 `hint: <原因>`(人工提示)。数据推不出顺序的作业归入"孤岛"层(无依赖边,仍纳入调度)。
|
|
354
|
+
|
|
355
|
+
hints.json 结构(全部可选):
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"before": [
|
|
360
|
+
{"first": "作业A", "then": "作业B", "reason": "先清洗后汇总"}
|
|
361
|
+
],
|
|
362
|
+
"cross_batch": [
|
|
363
|
+
{"consumer": "作业C", "dataset": "<dsId>", "reason": "读上一批快照"}
|
|
364
|
+
],
|
|
365
|
+
"exclude": ["废弃作业X"]
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
- `before`:加一条控制依赖边(血缘推不出来但业务要求先后)。
|
|
370
|
+
- `cross_batch`:声明跨批次读旧数据,plan 不会为它加边,且生成 `CrossBatch` 声明。
|
|
371
|
+
- `exclude`:从编排中剔除某些作业(按名或 ID)。
|
|
372
|
+
- 作业引用支持显示名或工作流 ID;重名时必须用 ID。
|
|
373
|
+
|
|
374
|
+
### deps verify 检查项
|
|
375
|
+
|
|
376
|
+
| 级别 | 代码 | 含义 |
|
|
377
|
+
|---|---|---|
|
|
378
|
+
| ERROR | MISSING_EDGE | A 读 B 的产出但编排中没有 B→A 路径(若刻意读旧数据,声明 CrossBatch) |
|
|
379
|
+
| ERROR | DUP_PRODUCER | 同一数据集被多个作业产出(产权冲突,先收敛产出方) |
|
|
380
|
+
| ERROR | REF_NOT_FOUND | 引用的作业工作流不存在(已删除/ID 错误) |
|
|
381
|
+
| ERROR | SELF_REF / NESTED_CYCLE | 自引用 / 嵌套编排成环 |
|
|
382
|
+
| WARN | NAME_MISMATCH | 节点显示名与线上工作流名不一致(edit 后重命名过) |
|
|
383
|
+
| WARN | PENDING_OUTPUT | 作业输出数据集尚未物化(从未成功运行过),血缘对账不完整 |
|
|
384
|
+
| WARN | UNUSED_CROSS | CrossBatch 声明没有匹配到任何血缘(可能写错 Consumer/Dataset) |
|
|
385
|
+
| INFO | CROSS_BATCH | 已声明的跨批次依赖(对账通过) |
|
|
386
|
+
| INFO | CONTROL_DEP | 依赖边没有血缘支撑(纯控制依赖,确认是否刻意) |
|
|
387
|
+
|
|
388
|
+
血缘提取覆盖:Python 节点(inputDatasets / outputDatasets)、数据流节点(actions 中的
|
|
389
|
+
INPUT_DATASET / OUTPUT_DATASET / INCREMENT_OUTPUT_DATASET)、嵌套子工作流(递归展开)。
|
|
390
|
+
作业定义拉取结果缓存在 `<workdir>/_deps_cache.json`(10 分钟 TTL),`--refresh` 强制重新拉取。
|
|
391
|
+
|
|
392
|
+
### 编排的运行与失败语义
|
|
393
|
+
|
|
394
|
+
- `guanwf run --wait --dir <workdir> --confirm` 运行主工作流,按边的顺序触发各作业子实例。
|
|
395
|
+
- 子作业失败 → 主实例失败,其 `After` 下游不执行;已成功的作业产出保留。
|
|
396
|
+
- 失败时 `run` 自动拉日志:失败的 SUB_PROCESS 节点 UI 日志为空,会自动下钻到
|
|
397
|
+
子实例逐任务打印(含 Python traceback 脚本输出),无需手动定位子实例。
|
|
398
|
+
- **推荐修复方式(增量恢复)**:修好失败作业(在作业自己的工作目录里改、save),
|
|
399
|
+
回编排目录 `guanwf run --recover --wait --confirm`——从恢复节点续跑;成功祖先和无关
|
|
400
|
+
分支不重跑,但恢复节点的全部 DAG 后继会重跑(即使后继先前为 SUCCESS)。
|
|
401
|
+
- 整链重跑:`guanwf run --wait --confirm`(已成功作业也会重跑;作业输出是 OVERWRITE 时幂等)。
|
|
402
|
+
- 作业节点的重试/超时用 `SubWorkflowConfig` 所在 TaskNode 的通用字段(edit 回读后在
|
|
403
|
+
task 层,当前 DSL 不展开;需要精细重试策略时在作业工作流内部配)。
|
|
404
|
+
|
|
405
|
+
### run --recover 的平台语义
|
|
406
|
+
|
|
407
|
+
`--recover` 找到最近一次 FAILURE 实例并自底向上恢复:
|
|
408
|
+
|
|
409
|
+
1. 列出恢复节点(FAILURE / STOP / KILL / NEED_FAULT_TOLERANCE);对其中的
|
|
410
|
+
SUB_PROCESS 节点,经 `select-sub-process` 定位子实例。
|
|
411
|
+
2. 递归先恢复子实例(`execute` + `START_FAILURE_TASK_PROCESS` + `update=true`,
|
|
412
|
+
使子实例吸收作业最新发布定义——否则会用失败时的旧定义快照重跑)。
|
|
413
|
+
3. 子实例成功后恢复父实例。8.2.0 会重跑恢复节点及其全部 DAG 后继;成功祖先和
|
|
414
|
+
无关分支保留原状态。
|
|
415
|
+
|
|
416
|
+
最外层实例只有传 `--wait` 才等待完成;嵌套 PROCESS 子实例为保证自底向上顺序始终等待。
|
|
417
|
+
`guanwf instance resume-failed <instanceId> --wait --timeout 900 --confirm` 可对指定实例使用
|
|
418
|
+
相同恢复器并调整长任务超时。若子工作流引用已从 A 改为 B,CLI 会阻止复用 A 的旧实例,
|
|
419
|
+
应直接新运行整条工作流。
|
|
420
|
+
|
|
421
|
+
限制:只有 FAILURE 状态的最近实例可恢复;若编排 DAG 结构已变更(加减节点/改依赖),
|
|
422
|
+
平台 `checkProcessChange` 会拒绝,此时直接 `guanwf run --confirm` 重跑整链。
|
|
423
|
+
不可与 `--node` / `--draft` / `--validate` 同用。
|
|
424
|
+
|
|
425
|
+
### 编排的定时调度
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
guanwf schedule info --dir <workdir>
|
|
429
|
+
guanwf schedule set --cron "0 0 2 * * ?" --dir <workdir> --confirm # 创建/更新并上线
|
|
430
|
+
guanwf schedule set --cron "0 0 2 * * ?" --param biz_date=2026-07-14 --dir <workdir> --confirm
|
|
431
|
+
guanwf schedule set --cron "0 0 2 * * ?" --offline --dir <workdir> --confirm # 只保存不上线
|
|
432
|
+
guanwf schedule event set --rule <datasetId>:<taskName> --param biz_date=2026-07-14 --dir <workdir> --confirm
|
|
433
|
+
guanwf schedule enable --dir <workdir> --confirm
|
|
434
|
+
guanwf schedule disable --dir <workdir> --confirm
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
- crontab 为 Quartz 表达式(秒 分 时 日 月 周 [年]),服务端校验合法性。
|
|
438
|
+
- `--failure-strategy`:已废弃的兼容参数,仅接受 `CONTINUE`。新离线开发固定提交 `failureStrategy=CONTINUE`;节点失败后的后继调度由 `FAILURE` / `ALL` 连线决定,显式传 `END` 会在本地校验阶段失败且不发送写请求。
|
|
439
|
+
- `--warning NONE|SUCCESS|FAILURE|ALL`:告警时机(默认 FAILURE)。
|
|
440
|
+
- `--auto-cancel-queued`:上一批未跑完时自动取消堆积的排队实例(长链路编排建议开启)。
|
|
441
|
+
- 已有调度时未指定的参数保留现状;只调度主工作流,被编排的作业自身不要再配调度
|
|
442
|
+
(避免同一作业被两条链路并发触发)。
|
|
443
|
+
|
|
444
|
+
## 命令闭环
|
|
445
|
+
|
|
446
|
+
### 新建工作流
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
guanwf create --name "我的工作流" --parent-dir <工作流目录ID> --dir <workdir>
|
|
450
|
+
# 默认生成数据流节点骨架: workflow.go + nodes/dataflow_1/etl.go
|
|
451
|
+
# --type PYTHON 生成 Python 节点骨架: workflow.go + nodes/python_1/script.py
|
|
452
|
+
# --type DB_DATAFLOW 生成数据库数据流骨架
|
|
453
|
+
# --type ORCHESTRATION 生成编排骨架(无初始节点,配合 deps plan 使用)
|
|
454
|
+
|
|
455
|
+
# 编辑 workflow.go 和节点源文件后:
|
|
456
|
+
guanwf export --dir <workdir>
|
|
457
|
+
guanwf save-draft --dir <workdir> --confirm
|
|
458
|
+
guanwf run --dir <workdir> --node "<节点名>" --validate --confirm # 校验(不创建真实输出数据集)
|
|
459
|
+
guanwf save --dir <workdir> --confirm # 正式发布
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
新增数据流节点时:`mkdir -p nodes/<节点ID>`,创建 `nodes/<节点ID>/etl.go`(guanetl DSL,
|
|
463
|
+
写法见 `references/ETL_AI_DEVELOP.md`),再在 `workflow.go` 中加 `DataflowNode(...)`。
|
|
464
|
+
|
|
465
|
+
### 编辑线上工作流(回读)
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
guanwf edit <workflowId> --dir <workdir>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
回读生成:
|
|
472
|
+
|
|
473
|
+
- `workflow.go`:节点 + 依赖结构(当前合约外或不满足结构化校验的节点生成 `RawTask` + 注释)
|
|
474
|
+
- 数据流节点 → `nodes/<id>/etl.go`(经 guanetl json2go,SQL 外置为 `*.sql`)
|
|
475
|
+
- Python 节点 → `nodes/<id>/script.py` + `nodes/<id>/python.json`
|
|
476
|
+
- 其他节点 → `nodes/<id>/task.json`
|
|
477
|
+
- `_layout.json`:线上画布坐标,导出时原样保留;新增节点自动分层布局补位
|
|
478
|
+
|
|
479
|
+
之后与新建流程相同:改源文件 → `export` → `save-draft` / `save`。
|
|
480
|
+
|
|
481
|
+
### 运行
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
guanwf run --dir <workdir> --confirm # 触发整个工作流(已发布版本)
|
|
485
|
+
guanwf run --dir <workdir> --wait --confirm # 等待完成
|
|
486
|
+
guanwf run --dir <workdir> --wait --logs --confirm # 完成后输出任务日志
|
|
487
|
+
guanwf run --dir <workdir> --node "<节点名>" --validate --confirm # 校验运行(不创建输出数据集)
|
|
488
|
+
guanwf run --dir <workdir> --node "<节点名>" --draft --wait --logs --confirm # 单节点真实运行草稿
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
`run` 会创建线上执行实例,升级后必须显式传 `--confirm`(兼容别名 `--yes`);
|
|
492
|
+
自动化脚本可先执行 `--dry-run` 检查目标、参数和请求计划。
|
|
493
|
+
正式启动实例前会从同一份最终执行快照重新解析参数覆盖、输出后置条件与 Python 内存门禁;
|
|
494
|
+
确认期间发生参数、Python 节点或输出槽位漂移时会在 `start-process-instance` 前失败关闭。
|
|
495
|
+
|
|
496
|
+
### 预览数据流节点
|
|
497
|
+
|
|
498
|
+
```bash
|
|
499
|
+
guanwf preview --dir <workdir> # 只有一个数据流节点时自动选中,预览其终端 action
|
|
500
|
+
guanwf preview <actionId> --dir <workdir> # 多个数据流节点时按 action id 定位
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
`preview` 针对**数据流节点内部的 action**(基于 export 的本地定义,无需先 save)。
|
|
504
|
+
Python 节点没有 preview API,校验用 `run --node "<节点名>" --validate`。
|
|
505
|
+
|
|
506
|
+
## save 的合并语义
|
|
507
|
+
|
|
508
|
+
`save-draft` / `save` 不是整体覆盖上传:
|
|
509
|
+
|
|
510
|
+
1. 读取 `_exported_workflow.json`(必须由 `export` 重新生成)
|
|
511
|
+
2. 从服务端拉取父工作流最新版本作为基底
|
|
512
|
+
3. tasks 按节点 id 做字段级合并:本地定义的字段覆盖,服务端独有字段(dsId、运行时注册信息等)保留
|
|
513
|
+
4. 节点成员按三方判断(服务端最新 + 本地 `_parent_merge_snapshot.json` + 本地导出):
|
|
514
|
+
本地快照里有、导出里删了的节点 → 删除;服务端有、本地快照不知道的节点(他人并发新增)→
|
|
515
|
+
保留并打印提示
|
|
516
|
+
5. dataflowJson 按 dataflow id 经 etlmerge 做 actions 字段级合并(成员判断同上)
|
|
517
|
+
6. 保存成功后刷新本地脱敏 `_parent_snapshot.json` 与受限权限 `_parent_merge_snapshot.json`,并把服务端回写的 Python 参数同步进 `python.json`
|
|
518
|
+
|
|
519
|
+
因此多人/多端并发修改同一工作流时,以服务端最新版本为基底合并,不会把别人新加的节点冲掉;
|
|
520
|
+
但同一节点的并发修改仍是后保存者覆盖。
|
|
521
|
+
|
|
522
|
+
保留他人并发新增节点时会做冲突校验,任一命中即中止保存(exit 1)并提示重新
|
|
523
|
+
`guanwf edit <工作流ID>` 同步后再修改:
|
|
524
|
+
|
|
525
|
+
- **断链**:并发新增的节点依赖(`preTasks` / `preTaskScheduleTypes`)了本地这次删除/改名的节点
|
|
526
|
+
- **重名**:并发新增的节点与本地节点显示名相同(name 是依赖引用键,必须全局唯一)
|
|
527
|
+
|
|
528
|
+
## 注意事项
|
|
529
|
+
|
|
530
|
+
- 节点显示名在工作流内必须唯一(`preTasks` 与 `--node` 都按名字引用)。
|
|
531
|
+
- `RawTask` 改名要改 `task.json` 的 `name` 字段,同时注意其他节点对它的依赖按名字解析。
|
|
532
|
+
- `workflow.go` 删除某节点后,对应 `nodes/<id>/` 目录可以保留(导出时忽略),但 save 会从
|
|
533
|
+
服务端定义中删除该节点;删除是真实生效的,操作前确认。
|
|
534
|
+
- 查询实例/日志的 API 需要 `domId`,`run` 命令自动从快照或服务端解析,无需手动处理。
|
|
535
|
+
- 列表查询用 `guancli workflow list`;workflow 引擎的 `list-paging` 请求体关键字段是
|
|
536
|
+
`searchVal`(不是 keyword)。
|