工作流中多个节点常常需要同一份取值(如环境标识、表名前缀、业务阈值),逐节点声明调度参数的维护成本高,且取值在运行启动后不可变。通过调度变量,可以在工作流的调度配置中统一定义变量,工作流内的节点在代码中直接引用,实现一处定义、整个工作流内生效;变量取值还支持在运行过程中被变量赋值节点改写,满足跨节点动态传值的场景。
调度变量为工作流级别能力,目前仅新版数据开发(DataStudio)支持。
核心概念
调度变量与调度参数是两类不同的配置项,区别如下。
|
对比项 |
调度变量 |
调度参数 |
|
定义位置 |
工作流的调度配置。 |
节点/工作流的调度配置。 |
|
取值确定性 |
运行前定义初始值,运行过程中可以被变量赋值节点修改。在变量赋值节点运行之后运行的节点,均可获得变更后的参数。 |
运行开始前即确定,运行过程中不变。 |
|
运行期改写途径 |
可通过变量赋值节点进行重新赋值。 |
不支持。 |
|
生效范围 |
所在工作流内的全部节点。 |
|
|
取值范围 |
定义参数时可以使用 |
|
|
引用语法 |
|
|
|
典型用途 |
环境标识、表前缀、阈值等多节点共用的取值;运行期动态传值。 |
按调度时间动态计算分区等业务时间。 |
使用场景
-
共用取值集中管理:环境标识、MaxCompute 项目名、表名前缀、告警阈值等多节点共用的取值,在工作流上定义一次,各节点直接引用,修改时只需调整变量取值,不再逐节点维护。
-
跨节点动态传值:配合变量赋值节点,上游节点在运行时改写调度变量,工作流内后续运行的节点直接读取最新值。相比赋值节点的上下文参数只能传给直接下游的一层节点,调度变量可以传给间接下游,无需为传值在节点间层层配置输入参数。
-
调试运行临时取值:调试运行工作流时,可为变量指定本次运行的取值,验证不同取值下的执行效果,不影响已保存的初始值。
变量取值的三种覆盖方式
调度变量的取值分为初始值(工作流调度配置中保存的值)与运行时取值(某一次运行实际生效的值)。三种覆盖方式的区别如下。
|
覆盖方式 |
操作入口 |
生效范围 |
是否修改初始值 |
|
运行时临时赋值 |
调试运行或运行工作流时,在运行配置中填写本次取值。 |
仅本次运行。 |
否 |
|
运行期改写 |
工作流中添加变量赋值节点,由其写入新值。 |
本次运行内,该节点之后运行的节点读最新值。 |
否 |
|
修改初始值 |
工作流调度配置中编辑变量取值,保存并发布。 |
后续所有运行(生产侧对应新实例)。 |
是 |
-
运行时临时赋值只覆盖同名变量的取值。运行配置中未填写的变量仍使用初始值;填写工作流上未定义的变量名不会生效。
-
运行期改写按节点运行顺序生效:变量赋值节点之后运行的节点读取改写后的最新值。该方式只作用于本次运行,不影响工作流上保存的初始值。
-
修改初始值需要重新发布工作流才能对生产生效;发布后新生成的调度实例使用新取值,已生成的实例不受影响。
前提条件
-
已进入新版数据开发(DataStudio)。
-
已创建周期工作流或手动业务流程,且具备工作流的编辑权限。
使用指南
步骤一:定义调度变量
-
进入数据开发页面,双击目标工作流,进入工作流编辑画布。
-
单击右侧调度配置,找到调度变量区域。
-
单击添加变量,填写变量信息。
配置项
说明
变量名
变量的唯一标识,在工作流内不可重复。建议仅使用字母、数字、下划线。
变量值
变量的初始值。
-
任务每次启动运行时,变量从该值开始生效。支持填写常量、工作空间参数与
$[yyyy-mm-dd]等时间表达式,详情可参考:调度参数来源及其表达式。 -
不支持在取值中引用工作流参数(如
${workflow.参数名})或赋值节点的输出值。
例如:
env=prod、ds_flag=$[yyyymmdd]。 -
-
保存工作流。
删除变量后,引用该变量的节点代码不会被自动修改。请在删除前确认各节点已不再引用,否则运行时该占位符将原样保留、不会被替换。
步骤二:在节点代码中引用变量
在工作流内节点的代码中,使用 ${workflow.variable.变量名} 格式引用。变量名支持字母、数字、下划线与中划线。
以SHELL节点为例,在工作流上配置了env和ds_flag,在代码编辑器中填写如下代码,并保存。
#!/bin/bash
echo "env=${workflow.variable.env}"
echo "ds_flag=${workflow.variable.ds_flag}"
任务运行时,系统在节点执行前将占位符替换为变量在本次运行中的当前值(初始值或本次运行改写后的值),再交给引擎执行。
-
调度变量与调度参数可以同时使用:
${workflow.variable.env}按调度变量规则替换,${bizdate}仍按调度参数规则替换为业务日期。 -
未知变量名不会报错替换失败:占位符原样保留在代码中,请确保引用的变量已在工作流上定义。
-
调度变量只能在代码区引用。在调度配置的脚本参数中,参数值里书写
${workflow.variable.变量名}不会取到变量值。 -
不支持取变量值中的一部分,
${workflow.variable.变量名[0][1]}、${workflow.variable.变量名.name}等写法无效。需要拆分取值时,在变量赋值节点中用 Shell 或 Python3 计算后写入另一个变量。
步骤三:测试运行
-
在工作流编辑画布,单击页面上方的运行。
-
在填写运行参数表单的工作流变量列,按需修改本次运行的取值。此处的赋值为调试运行时临时赋值,仅在本次运行时生效,也不会改变变量的初始赋值。
-
执行运行,并在节点运行日志中检查变量替换结果是否符合预期。
运行配置中修改的变量取值仅对本次运行生效,不会写入工作流保存的变量初始值。
步骤四:使用变量赋值节点在运行期修改变量
需要在运行过程中修改变量取值时,向工作流中添加变量赋值节点。该节点属于通用节点,支持 Shell 与 Python3,通过在脚本中向标准输出打印赋值标记写入新值。生效规则如下。
-
每次工作流运行时,系统会为本次运行生成一份调度变量副本。工作流内节点执行时,代码中的
${workflow.variable.变量名}从该副本取值替换。 -
变量赋值节点执行前,其脚本中的
${workflow.variable.变量名}也会被替换为变量当前值,因此脚本内可以先读取变量再计算新值。 -
脚本执行时,通过向标准输出打印赋值标记写入新值。赋值标记支持两种格式:
-
单行格式 :
##WORKFLOW_VARIABLE::变量名=值; -
多行格式:
##WORKFLOW_VARIABLE_BEGIN::变量名起始、以##WORKFLOW_VARIABLE_END::变量名结束,适用于取值包含换行的场景,如多行数据。
# 读取变量 env,计算后改写变量 ds_flag echo "current env: ${workflow.variable.env}" echo "##WORKFLOW_VARIABLE::ds_flag=20260903" # 多行赋值 echo "##WORKFLOW_VARIABLE_BEGIN::result_json" echo '{"name":"shirt","count":50}' echo '{"name":"coat","count":120}' echo "##WORKFLOW_VARIABLE_END::result_json" -
-
节点执行成功后,系统解析标准输出中的赋值标记,将新值写回本次运行的变量副本。该节点之后运行的节点,引用
${workflow.variable.变量名}得到的即为新值。
-
只能给工作流上已定义的变量赋值。给未定义的变量赋值不会生效;如果一个赋值标记都不匹配已定义变量,节点会执行失败。
-
改写只对本次运行生效,不影响工作流调度配置中保存的初始值,也不影响其他运行实例。节点运行失败时不解析赋值标记,变量保持改写前的值。
-
单次运行中变量数据总量上限默认为 2 MB。
-
变量赋值节点仅支持在 Serverless 资源组上运行,且要求标准版及以上版本。完整的配置项、使用限制与多分支示例请参见“变量赋值节点”。
步骤五:发布与验证
-
完成测试后,提交并发布工作流至生产环境。调度变量随工作流一并发布。
-
发布成功后,进入运维中心,确认周期任务中变量替换结果符合预期。
如果生产任务的变量取值不符合预期,请确认工作流是否发布成功。
使用示例:多分支工作流中使用调度变量
以下示例构建一条带分支与汇合的链路:Shell 变量赋值节点产出统计结果,下游分三支并行消费(一支接力改写日期、一支按阈值校验、一支写入告警文案),汇合节点读取全部变量的最终值。常量集中定义、运行期结果沿依赖顺序传递,均不需要在节点间重复声明。
步骤一:定义变量
在工作流调度配置中添加 7 个变量。
|
变量名 |
变量值(初始值) |
用途 |
|
env |
daily |
环境标识,组合表名使用。 |
|
tbl_prefix |
dwd_ |
表名前缀,组合表名使用。 |
|
ds_flag |
(留空) |
日期标识,被变量赋值节点接力改写。 |
|
stats_json |
{} |
统计结果,Shell 变量赋值节点以多行格式写入。 |
|
chain_flag |
(留空) |
接力标记,Python3 变量赋值节点写入。 |
|
quality_threshold |
100 |
质量校验阈值。 |
|
alert_msg |
(留空) |
告警文案,告警分支变量赋值节点以多行格式写入。 |
步骤二:搭建节点链路
按下表创建 6 个节点并连接依赖:set_ds_flag 分三支,summary_report 汇合三支。
|
节点 |
类型或语言 |
上游 |
职责 |
|
set_ds_flag |
变量赋值节点 / Shell |
无 |
读初始值;写入 ds_flag、stats_json。 |
|
assign_next_day |
变量赋值节点 / Python3 |
set_ds_flag |
读新 ds_flag,再改写并写入 chain_flag。 |
|
assign_alert_msg |
变量赋值节点 / Python3 |
set_ds_flag |
用变量拼装告警文案,以多行格式写入 alert_msg。 |
|
quality_check |
Python 节点 |
set_ds_flag |
解析 stats_json,按 quality_threshold 校验。 |
|
prepare_report |
Python 节点 |
assign_next_day |
读接力后的 ds_flag、chain_flag、stats_json。 |
|
summary_report |
Python 节点 |
quality_check、assign_alert_msg、prepare_report |
读全部变量最终值,输出汇总。 |
三个变量赋值节点的代码如下。
-
变量赋值节点set_ds_flag,设置变量赋值节点的语言类型为SHELL。
# set_ds_flag(变量赋值节点,Shell) #!/bin/bash echo "env=${workflow.variable.env} tbl=${workflow.variable.tbl_prefix} ds_flag(before)=${workflow.variable.ds_flag}" echo "##WORKFLOW_VARIABLE::ds_flag=20260903" echo "##WORKFLOW_VARIABLE_BEGIN::stats_json" echo "{\"table\":\"${workflow.variable.tbl_prefix}user_trade_${workflow.variable.env}\",\"rows\":120,\"ok\":true}" echo "##WORKFLOW_VARIABLE_END::stats_json" -
变量赋值节点assign_next_day,设置节点语言类型为python3。
# assign_next_day(变量赋值节点,Python3) print("[b_py] ds_flag(a)=" + "${workflow.variable.ds_flag}") stats = """${workflow.variable.stats_json}""" print("[b_py] stats_json=" + stats) print("##WORKFLOW_VARIABLE::ds_flag=20260904") print("##WORKFLOW_VARIABLE::chain_flag=py-touched") -
变量赋值节点assign_alert_msg,设置节点语言类型为python3。
# assign_alert_msg(变量赋值节点,Python3) msg_table = "${workflow.variable.tbl_prefix}" + "user_trade_" + "${workflow.variable.env}" print("[alert_assign] build alert for " + msg_table) print("##WORKFLOW_VARIABLE_BEGIN::alert_msg") print("[DAILY-ALERT] table: " + msg_table) print("[DAILY-ALERT] ds: ${workflow.variable.ds_flag}") print("please contact: dw-group-01") print("##WORKFLOW_VARIABLE_END::alert_msg")
三个消费节点的代码如下。
-
python节点quality_check。
# quality_check(Python 节点) rows = __import__("json").loads("""${workflow.variable.stats_json}""").get("rows", 0) ts = int("${workflow.variable.quality_threshold}") print("[quality] rows=%s threshold=%s -> %s" % (rows, ts, "PASS" if rows >= ts else "WARN")) -
python节点prepare_report。
# prepare_report(Python 节点) print("[prepare] ds_flag=" + "${workflow.variable.ds_flag}" + " chain=" + "${workflow.variable.chain_flag}") stats = """${workflow.variable.stats_json}""" print("[prepare] report table rows from stats_json=" + stats) -
python节点summary_report。
# summary_report(Python 节点) print("[summary] ds_flag(final)=" + "${workflow.variable.ds_flag}") print("[summary] chain=" + "${workflow.variable.chain_flag}") stats = """${workflow.variable.stats_json}""" print("[summary] stats_json=" + stats) msg = """${workflow.variable.alert_msg}""" print("[summary] alert_msg=" + msg)
取值为 JSON 等含引号的内容时,替换结果会直接代入代码,请按宿主语言的语法规则包裹(Python 使用 """..."""),否则会触发脚本语法错误。
步骤三:运行并验证结果
返回工作流画布,点击工具栏的运行按钮。运行工作流后,各节点日志中的关键输出如下,变量值随节点运行顺序依次传递。
|
节点 |
日志关键输出 |
说明 |
|
set_ds_flag |
|
运行开始为初始值;随后写入 ds_flag=20260903 与 stats_json。 |
|
assign_next_day |
|
读到上一步的新值;随后改写为 20260904、写入 chain_flag。 |
|
assign_alert_msg |
|
tbl_prefix 与 env 已组合成表名;随后写入多行 alert_msg。 |
|
quality_check |
|
解析 stats_json 成功并完成阈值校验。 |
|
prepare_report |
|
读到接力后的最终日期与接力标记。 |
|
summary_report |
|
三分支汇合后读到全部变量最终值。 |
上述改写仅作用于本次运行,不影响工作流保存的初始值:运行结束后再次打开调度变量面板,ds_flag 初始值仍为 unset、alert_msg 仍为空。
父子工作流之间的变量传递
工作流通过 subprocess 节点引用另一个工作流时,被引用的工作流即为子工作流。父子工作流各自定义自己的调度变量,作用域互不重叠。需要把父工作流的取值传给子工作流时,在父工作流的 subprocess 节点上重置子工作流的变量:将子工作流变量的重置值填为父工作流变量的引用值,运行时子工作流即以父工作流传入的值开始。
subprocess 节点的参数区分为工作流参数与工作流变量两个区块。工作流变量区块展示子工作流已定义的变量名、变量值(子工作流中保存的初始值)与重置值,其中仅重置值可编辑。
三种传递场景
|
场景 |
配置方式 |
运行时效果 |
|
父工作流给子工作流的变量做首次赋值,后续由子工作流内部再改写。 |
在 subprocess 节点上重置该变量,重置值填父工作流变量的引用值;同时在子工作流内保留变量赋值节点。 |
子工作流以父工作流传入的值开始运行,变量赋值节点运行后的下游节点改用新值。 |
|
父工作流的取值在子工作流全程生效。 |
在 subprocess 节点上重置该变量,且子工作流内不配置针对该变量的变量赋值节点。 |
子工作流内所有节点读到的都是父工作流传入的值。 |
|
子工作流不受父工作流影响。 |
在 subprocess 节点上不重置该变量(重置值留空)。 |
子工作流使用自己调度配置中保存的初始值。 |
配置步骤
-
在父工作流的编辑画布中,添加SUBPROCESS节点。
-
在工作流变量区块找到需要传值的子工作流变量,后续也可以单击画布中节点右上角的编辑图标再次修改。
-
在重置值中填入父工作流变量的引用值,例如
${workflow.variable.env}。留空表示不重置,子工作流沿用自己的初始值。 -
保存并发布父工作流。子工作流的变量定义有变动时,子工作流也需重新发布。
-
只能重置子工作流中已定义的变量。子工作流未定义的变量不会出现在该区块,也无法通过 subprocess 节点新建。
-
变量的作用域仍以工作流为边界。子工作流内部节点引用
${workflow.variable.变量名}取到的是子工作流自己的变量(取值可能已被父工作流重置),不能直接引用父工作流的变量。 -
传递为父工作流到子工作流的单向传递,且仅在本次运行内生效,不会修改子工作流保存的初始值。
注意事项
-
作用域限制:调度变量仅对所在工作流内的节点生效,不同工作流之间的变量互不可见;跨工作流复用时需要分别定义。
-
同名限制:同一工作流内变量名不可重复。调度变量与调度参数是两条独立的替换通道,引用语法不同(
${workflow.variable.变量名}对${参数名})。 -
参数与变量的选择:取值需要随调度时间动态计算(如业务日期)时使用调度参数;取值为常量或运行期需要改写时使用调度变量。
-
初始值生效时机:每次运行启动时变量以初始值开始;运行过程中被改写的值仅作用于本次运行,不会影响初始值。
-
运行期改写途径:运行期改变量取值只能通过变量赋值节点完成;普通节点代码中引用变量为只读语义,节点代码本身无法修改变量取值。赋值节点不能改写调度变量,它通过节点上下文参数(
outputs)向直接下游的一层节点传值。
常见问题
-
Q:调度变量可以在手动业务流程中使用吗?
A:可以。周期工作流与手动业务流程均支持定义调度变量,定义与引用方式一致。
-
Q:调试运行改的变量值,会影响生产调度吗?
A:不会。运行配置中的取值仅本次运行生效;生产调度使用工作流上保存的变量初始值及使用变量赋值节点改写后的结果。
-
Q:引用了一个未定义的变量会怎样?
A:引用未定义的调度变量不会报错,占位符
${workflow.variable.变量名}会原样保留在代码中参与执行(例如 Shell 场景中可能进一步引发脚本语法错误)。请确保引用的变量已在工作流上定义。 -
Q:调度变量的取值可以写时间表达式吗?
A:可以。变量取值支持常量、工作空间参数与
$[yyyy-mm-dd]等时间表达式。但取值中不能引用工作流参数(如${workflow.参数名}),也不能引用赋值节点的输出值。 -
Q:调度变量发布后多久生效?
A:调度变量随工作流发布生效。已生成的实例不受影响,下一次调度生成的实例使用发布后的取值。