尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OneUptime Workflow 变量详解:全局变量、本地变量与组件输出的引用机制及源码实现

OneUptime Workflow 变量详解:全局变量、本地变量与组件输出的引用机制及源码实现 OneUptime Workflow 变量详解全局变量、本地变量与组件输出的引用机制及源码实现【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptimeWorkflow 是 OneUptime 中把触发事件转化为自动化动作建事件、发通知、调 API的引擎而变量是数据在触发器、各组件块之间流动的方式。本篇以官方文档 variables 为骨架结合 运行器实现、模板替换引擎 和 变量数据模型完整讲清两级变量与组件输出的引用语法、可用位置、{{#each}}数组循环、通过 API 轮换变量值的模式以及每个坑背后的源码原因。变量的三个数据层级文档将 workflow 中的数据划分为三个层级全局变量Global variables项目级定义一次、所有 workflow 复用本地工作流变量Local variables只属于单个 workflow且在每次运行时重新装载本地变量只在当前执行中生效每次新执行都从零开始组件输出Component outputs每个触发器和组件在执行中产生的输出可用引用语法在后续块中取用。从源码看这个三层结构对应运行器中的一个StorageMap对象RunWorkflow.ts#L226-L238export interface StorageMap { local: { variables: Dictionarystring; components: { [x: string]: { returnValues: JSONObject }; }; }; global: { variables: Dictionarystring; }; }getVariables方法RunWorkflow.ts#L1130-L1194在每次执行开始时从数据库装载变量本地变量按workflowId查询全局变量则用workflowId: QueryHelper.isNull()查询——也就是说全局变量就是workflowId为空的那些行它们与普通 workflow 变量存在同一张表里靠是否为空的workflowId划出独立命名空间。每行变量被展平成storageMap[scope].variables[name] content的纯字典这正是引用语法{{global.variables.NAME}}/{{local.variables.NAME}}的解析来源{{...}}内的文本会被按.拆分逐段在这棵字典树上deepFindVMAPI.ts#L375-L426。全局变量项目级的只存不改值仓库全局变量用于存放 API 密钥、URL、频道名这类不想复制到十个 workflow 里的值。在 UI 中位于Workflows → Global variables文档中为Arbejdsgange → Globale variabler。每个变量有四个字段字段说明Name名称引用它的标识。至少两个字符无空格仅允许字母、数字、连字符和下划线。UPPER_SNAKE_CASE是好习惯因为引用时格外醒目Description描述可选自由文本提醒自己变量用途Secret秘密开启后该值会从执行日志和步骤追踪中抹除Content内容值本身。长文本字段多行值也没问题在任意 workflow 中用如下语法引用{{global.variables.NAME}}例如把 PagerDuty 密钥存为PAGERDUTY_KEY后任何块都可以写{{global.variables.PAGERDUTY_KEY}}。编辑器只保存引用而 workflow 日志会对解析后的秘密值做脱敏。数据模型印证了这些字段与约束WorkflowVariable.tsname列带有UniqueColumnBy([workflowId, projectId])约束L268——同一项目内全局变量名唯一同一 workflow 内本地变量名唯一两个命名空间互不冲突content列是VeryLongText类型与文档长文本字段的说法一致整个表挂在 Growth 订阅计划之上TableBillingAccessControl({ create: PlanType.Growth, read: PlanType.Growth, ... })L28-L33即文档所述全局变量与 workflow 变量是 Growth 计划的功能API 端点为CrudApiEndpoint(new Route(/workflow-variable))L74对应后文PUT /api/workflow-variable/id的调用路径。文档特别强调的操作语义变量只能被创建和删除不能被编辑——表格里没有编辑按钮。想改值要么删除重建要么走 API 更新。这一不可逆设计在更新钩子中有一处更严格的安全含义见 API 更新变量 一节。本地工作流变量本地变量只对一个 workflow 生效在该 workflow 左侧菜单的Workflow variables下管理引用语法为{{local.variables.NAME}}从实现看本地变量与全局变量走完全相同的装载逻辑只是查询条件从workflowId: null换成具体的 workflow id。需要注意每次执行都是全新装载这一点运行器在suspendRunSleep 挂起恢复路径中会刻意不把变量值写进resumeData持久化状态恢复时重新读取so secrets never live in resumeDataRunWorkflow.ts#L479-L486——这保证了挂起—恢复之间变量值的变化会被自然拾取也保证秘密值不落盘到恢复状态里。组件输出引用前序块的数据每个触发器和组件在执行时都会产出返回值语法为{{local.components.COMPONENT_ID.returnValues.FIELD_ID}}其中COMPONENT_ID是块的Identifier显示在块上的短 id如api-get-1不是显示名称。可以在块的 ID 区段重命名它但重命名会破坏所有指向它的引用——与重命名变量的后果相同FIELD_ID是所选返回值的 id。文档给出的三类典型示例API组件 id 为lookup-user时状态码是{{local.components.lookup-user.returnValues.response-status}}响应体是{{local.components.lookup-user.returnValues.response-body}}Run Custom JavaScript组件 id 为transform时返回值为{{local.components.transform.returnValues.returnValue}}事件类触发器如On Create Incident只返回一个值model再向下钻取。id 为incident-on-create-1的触发器事件标题是{{local.components.incident-on-create-1.returnValues.model.title}}。编辑器提供组件值选择器component value picker用它插入引用而不是手写它能填上运行器期望的准确 id使引用与显示名解耦。源码层面每个组件执行完成后运行器执行RunWorkflow.ts#L640-L642storageMap.local.components[stackItem.node.id] { returnValues: result.returnValues, };注意这里的键是node.id即块的 Identifier——所以引用路径中的COMPONENT_ID必须是 Identifier 而不是标题重命名 Identifier 后所有旧引用都会失效。后续的{{...}}解析正是拿这些 id 去storageMap.local.components下逐段deepFind。变量可以在哪些位置使用几乎所有文本字段都接受变量引用API 块的 URLSlack、Teams、Discord、Telegram、Email 的正文消息文本邮件的主题与正文Header 与 body 字段位于字符串值内部时If / Else条件块属于 Conditions 分类两侧的比较表达式。JSON 字段的规则是变量可以用在字符串值内部但不能作为键。如果一处引用单独占满整个值它会以原始方式插入——即对象/数组值会按 JSON 文本整体代入这样你就能把一个完整对象放进 JSON 字段。需要动态构造结构时文档建议用Run Custom JavaScript块先构建结构再把其输出传给下一块。替换引擎的源码与这些规则一一对应VMAPI.ts#L24-L136整值引用检测if (valueToReplaceInPlaceCopy.trim() {{ variable }})命中时直接用解析值对象会JSON.stringify成格式化文本替换不走嵌入字符串路径——这就是单独占满即原始插入的实现JSON 转义当所在字段是 JSON 类型isJSON为真时解析值会先经过serializeValueForJSON转义反斜杠、引号、换行等L339-L372避免把含引号或换行的值塞进 JSON 字符串字面量后导致解析失败替换用函数的replace形式而非字符串形式防止解析值里的$、$1等被当作替换模式——注释里特别提到解析值50$会自我改写的问题L108-L119。组件参数在进入替换之前由getComponentArgumentsRunWorkflow.ts#L955-L1024统一处理对每个声明过的参数取值调VMAPI.replaceValueInPlace(storageMap, content, isJSON)替换完成后若参数类型是 JSON/Query/Select 且结果是字符串会再JSON.parse一次——所以JSON 字段里变量只能进字符串值的另一半含义是替换后整段文本必须仍是合法 JSON否则该次执行会以Invalid JSON provided for argument ...报错。Run Custom JavaScript 块不自动注入变量——沙箱里不会凭空出现任何值。正确做法是把{{global.variables.NAME}}或任意组件引用写进该块的 JSON 参数Arguments这些值在脚本执行前被替换完成并以args到达脚本内。数组循环{{#each ...}}...{{/each}}文本字段内支持{{#each path}}...{{/each}}遍历数组循环体内{{property}}读取当前元素的属性{{index}}是当前下标从 0 计{{this}}是元素本身元素为普通值数组时循环体内的变量名会被trim因此松散的空格无害——这是全系统唯一的例外。实现上由expandEachLoopsVMAPI.ts#L154-L280完成在普通变量替换之前先展开循环。几个值得知道的细节路径解析结果不是数组时整个块被删除替换为空串而不是留下字面文本对象元素会被合并进一个作用域化 storageMap元素属性优先{{status}}指向元素解析不到再回落到父级路径{{requestBody.receiver}}仍可用见replaceLoopVariablesL288-L336支持嵌套{{#each}}按嵌套深度配对{{/each}}有 100 次迭代的安全上限防止死循环未配对的{{#each}}会被剥掉。deepFind还支持数组下标语法items[0]、items[last]L385-L411可以精确取某一项与循环互为补充。实战示例示例一把 webhook 转成 OneUptime 事件假设 webhook 到达body 为{ service: checkout, status: failed }。构造流程Webhook触发器id 为ci-webhookIf / Else块取 webhook 的 Request Body 输出选status属性操作符右侧failed从Yes分支接Create One Incident块标题CI build failed: {{local.components.ci-webhook.returnValues.request-body.service}}描述See {{local.components.ci-webhook.returnValues.request-body.url}} for the logs.示例二在 API 调用中使用秘密一个调用 PagerDuty 的 workflow把PAGERDUTY_KEY存为秘密全局变量API块的Authorization头写成Token token{{global.variables.PAGERDUTY_KEY}}。密钥因此既不出现在 workflow 定义里也不出现在日志里——秘密脱敏的链路是getSecretWorkflowVariableValues收集isSecret变量的内容并按长度降序排序防止短密钥先替换、留下长密钥的尾巴redactSecretsFromString在执行日志持久化前把每一处出现替换为[REDACTED]SecretRedaction.ts#L28-L99。这一步在cleanLogs中执行RunWorkflow.ts#L822-L835步骤追踪的argumentValues、returnValues和errorMessage也走同一套脱敏redactWorkflowStepTrace键名也会被扫描——因为变量可以被替换进 JSON 属性名比如 HTTP 头名。示例三串联两次 API 调用第一次调用产出的 id 被第二次调用消费API组件lookup-order用选择器把手动触发器的 JSON email 字段插入GET /orders?email...API组件cancel-orderPOST /orders/{{local.components.lookup-order.returnValues.response-body.id}}/cancel。如果lookup-order失败会走它的Error输出端口而不是Success端口。把 Error 端口连到 Email 或 Slack 块错误就不会无声无息。API 更新变量轮换 token 的自动化模式一个常见模式是按计划轮换访问密钥从第三方取新 token再写回变量下次执行自动拾取。做法是用API块调用 OneUptime APIPUT /api/workflow-variable/variable-id带ApiKey头以及——文档特别指出这是人们最常卡住的地方——要改的字段必须包在data对象里{ data: { content: {{local.components.get-token.returnValues.response-body.access_token}} } }不带data包裹的扁平 body 会被 400 拒绝。只发确实要改的字段name和description可以不出现在 payload 里。API 密钥需要Edit Workflow Variables权限且不需要读权限——更新操作不回读该行。数据模型印证了这一点content列的列级 ACL 中read: []任何人都不能通过 API 读出内容值WorkflowVariable.ts#L306-L329update 权限列表正是ProjectOwner / ProjectAdmin / EditWorkflowVariableL250-L254。这正是变量可以作为 token 的停放点的原因content只能写、不能读再标记为秘密值还会从执行日志和步骤追踪中抹掉。更新钩子里有两个安全细节WorkflowVariableService.ts都是围绕只能写、不能读这个面设计的秘密标记是棘轮只能收紧不能放松onBeforeUpdate检测到把isSecret从 true 改成 false 的写操作时直接抛错L76-L138。理由content经 API 不可读若允许一个可写不可读的调用者清除秘密标记、触发一次执行就能从日志里把值读出来。要取消秘密删除变量重建即可重命名会被查重重命名时按项目、workflowId 或workflowId 为 null的全局命名空间做大小写不敏感的唯一性检查重名报 400L144-L206。这堵住了一个静默故障运行器把变量装进普通字典重名会让后加载的行悄悄覆盖前者workflow 不报错、只是用错值。坑位与故障行为文档陷阱一节逐条对应源码行为值得逐条记住用选择器插入引用。选择器填的是运行器期望的组件 id、返回值 id 与变量名且引用与显示名解耦重命名显示名不会破坏引用。变量名区分大小写。{{global.variables.MyKey}}与{{global.variables.mykey}}是两个不同的键。字典查找是精确匹配deepFind不做任何大小写折叠。解析失败的引用原样保留不会被清空。引用一个不存在的东西不是错误也得不到空串花括号文本被原样发出去。写错一步 id 的{{local.components.api-get-1.returnValues.body}}会一字不差地出现在 Slack 消息、URL 或请求体里而执行仍报Executed。实现上replaceValueInPlace对解析不到的路径直接continueVMAPI.ts#L87-L90作为补偿logUnresolvedReferencesRunWorkflow.ts#L922-L953会逐参数对比替换前后文本把进去之后原样出来的引用逐一点名写进执行日志例如Warning: {{local.componets.x}} in url did not resolve to anything and was left as literal text. Check the step id and the return value name.所以排查消息里为什么出现了花括号时先看执行日志里这条警告行。构建器无法校验变量名。构建器会在保存前标记匹配不上的组件引用未知步 id、未知返回值、畸形根路径但它看不到变量是否存在——被重命名/删除的变量要到执行日志里才会暴露。这与服务层的注释一致Unresolved references are not an error at run time。花括号内的空格不会被 trim。{{ local.variables.NAME }}与{{local.variables.NAME}}是不同的键前者永远不会被解析。唯一的例外是{{#each}}循环体内那里变量名会被 trim。延伸阅读Workflow 组件参考——每个块产生的输出全列表Workflow 执行与日志——查看每次执行后每个变量的实际取值Workflow 配置与安全——什么值适合放进全局变量。【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表