ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

OneUptime 工作流运行与日志(Runs Logs)深度指南:状态机、步骤追踪与故障排查实战

2026/9/18 22:36:35 拓冰建站 浏览量
OneUptime 工作流运行与日志(Runs  Logs)深度指南:状态机、步骤追踪与故障排查实战 OneUptime 工作流运行与日志Runs Logs深度指南状态机、步骤追踪与故障排查实战【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime每次工作流被触发后OneUptime 都会将“何时运行、是否成功、每个块做了什么”完整记录为一个run运行记录。这篇指南以官方文档 App/FeatureSet/Docs/Content/en/workflows/runs-and-logs.md 为骨架结合仓库中工作流执行器与日志模型的源码实现系统讲解 run 的查找入口、七种状态语义、Steps/Full Log 双标签阅读方法以及“没运行”“后续块没执行”“变量为空”“手动能跑触发不能跑”四类高频问题的排查思路并揭示 30 天保留策略与敏感信息脱敏的底层机制。Run 是什么在 OneUptime 中每次工作流被触发系统都会持久化一条运行记录记录内容包括触发时间、运行状态、每个步骤块的输入输出与耗时。这条记录就叫run。它的用途有三个确认验证工作流确实按预期执行了调试定位失败步骤、未解析的变量引用、超时的环节追溯回顾过去一段时间的自动化活动。从源码角度看一条 run 对应数据库中的一条WorkflowLog记录模型定义见 WorkflowLog.ts。该表以TableMetadata({ tableName: WorkflowLog })声明核心字段包括字段类型说明logsVeryLongText运行器逐行输出的原始日志workflowStatusWorkflowStatus运行状态见下节状态表startedAt/completedAtDate开始与结束时间resumeAtDateSleep 块挂起后的计划恢复时间仅 Waiting 状态时设置resumeDataJSON内部使用的执行状态快照用于 Sleep 后恢复不通过 API 暴露stepTraceJSON结构化步骤追踪即前端 Steps 标签的数据源表上还声明了Index([workflowStatus, createdAt])注释明确说明这是供 Worker 扫描“Scheduled 但超时未执行”或“Timeout”的运行使用的。在哪里找到 Run文档给出了三个入口整理如下页面你能看到的内容Workflows → Runs Logs项目内所有工作流的全部运行记录。可按工作流名称、状态和时间过滤。Workflow → Runs Logs仅某一条工作流的运行记录。此处的过滤器是Run ID而不是工作流过滤器。单条 run通过 run 行上的View Logs按钮打开——run 行本身不可点击。这三个 UI 文案Runs Logs、Run ID、View Logs都能在 Dashboard 前端国际化词条中找到例如 en.json 中分别对应 Runs Logs、Run ID 与 View Logs 键。Run 的七种状态文档列出了全部运行状态与后端枚举 WorkflowStatus.ts 一一对应UI 显示状态枚举值含义ScheduledScheduled触发器已触发run 已进入队列等待运行器接管通常只持续几分之一秒。若 Scheduled 状态超过 5 分钟仍未执行视为失败——说明没有运行器拾取它。RunningRunning工作流正在执行中。长耗时块会让 run 一直停留在此状态。WaitingWaitingrun 停在Sleep块上会自行恢复。挂起期间不占用任何 Worker。ExecutedSuccessrun 正常到达终点没有失败。UI 上的徽标文字是Executed而非 Success但后端枚举值即Success。ErrorErrorrun 因某个块抛出错误而停止。以下情况也会落到此状态已入队但从未被拾取、Sleep 挂起后恢复丢失、调度 cron 表达式无法解析、或 run 执行中途工作流被禁用。TimeoutTimeoutrun 运行时间超过允许上限。详见 configuration.md。Execution Exceeded Current PlanWorkflowCountExceeded项目在过去 30 天内的运行次数已用尽或订阅未缴费。run 会被记录但不会执行。仅 OneUptime Cloud 适用。要点一走 Error 输出分支不等于运行失败。当一个块把控制流转交给自己的Error输出端口例如 API 块收到 4xx 响应时并不会让整个 run 失败。错误分支会正常执行run 最终仍然以Executed结束只是该步骤本身在界面上会以红色绘制方便你定位。从源码看这个行为的依据位于 RunWorkflow.ts 的recordStep方法它用failed Boolean(params.errorMessage || params.executedPort error)判断步骤是否标记为失败。也就是说只要某一步“走的是 error 端口”或“携带错误信息”该步骤就会被记录为WorkflowStepStatus.Error但 run 整体是否失败取决于主循环是否抛出了异常而非单个步骤走了 error 分支。要点二UI 文案与后端枚举的差异。文档中的 Executed 对应枚举SuccessExecution Exceeded Current Plan 对应枚举WorkflowCountExceeded枚举原始字符串为Workflow Count Exceeded。阅读日志或通过 API 查询状态时请以枚举值为准。状态流转的源码视角RunWorkflow.ts 的runWorkflow是状态流转的核心实现入队时QueueWorkflow.ts 的addWorkflowToQueue若为立即执行先创建一条workflowStatus Scheduled的WorkflowLog运行器接管时runWorkflow通过updateColumnsByIdWithoutHooks把状态更新为Running并记录startedAt恢复执行时保留原始开始时间执行循环从 Trigger 出发按 FIFO 栈逐块执行每一步通过recordStep追加到stepTrace正常结束状态写为Success写入完整logs、stepTrace、completedAt并清空残留的resumeData/resumeAt异常结束捕获到TimeoutException则写Timeout其余错误写Error并同样落盘日志与步骤追踪。值得注意的是WorkflowLog的所有状态写入都走updateColumnsByIdWithoutHooks快速路径——该表没有 workflow/audit/realtime 装饰器且 Dashboard 日志查看器是轮询读取而非依赖实时事件因此跳过完整更新管线可省去大量每 run 记账开销。如何阅读一次 Run点击 run 的View Logs按钮即可打开Workflow Run视图它包含两个标签页。Steps 标签每个执行过的块对应一行按执行顺序排列。每行显示块的标题title块的组件 idcomponent id耗时durationInMs输出的去向→ success、→ error、→ yes等端口名。展开一行可看到两块详情Received—— 块实际收到的设置此时所有变量已经完成解析替换Returned—— 块产生的结果。失败步骤为红色且默认展开错误信息显示在Received上方。在源码中这些数据对应WorkflowStepTraceEntry结构见 StepTrace.tscomponentId、metadataId、title、status、startedAt、completedAt、durationInMs、argumentValues即 Received、returnValues即 Returned、executedPort即输出端口与可选的errorMessage。每个步骤由recordStep在块执行后或抛错时写入。两个值得注意的细节组件 id 就是变量引用的钥匙。步骤标题下方打印的 component id正是可以粘贴进{{local.components.id.returnValues.…}}引用中的字符串这是快速写对变量引用的最快方式。run 只保留最近 100 步。当步骤数超过上限时最旧的步骤会被丢弃视图上会出现一条琥珀色提示说明更早的步骤已被移除。源码层面这两个行为都在 StepTrace.ts 中定义MAX_TRACE_STEPS 100appendTraceStep在步数超限时执行steps.slice(steps.length - MAX_TRACE_STEPS)并置truncated: true前端据此显示提示。注释还解释了为何保留尾部而非头部一个失败的 run 是从末尾往回读的弄坏它的恰恰是最后一步。Full Log 标签这是运行器打印的逐行原始日志包括各块自己记录的内容。当 Steps 视图无法解释失败原因时用它来排查。源码中每行日志的格式为时间戳: 内容见RunWorkflow.log方法内容既包括执行器自身的记录Executing Component: id、Component Args:、Data Returned、Executing Port: title等也包括块通过options.log(...)回调输出的任意内容。脱敏与截断Steps 视图展示的数值是变量填充之后、块实际看到的数值但有两类例外Secret 与标记为敏感sensitive的字段会被脱敏显示为[REDACTED]超长值会被截断超过长度上限的值以… (truncated)结尾。源码实现有两层防线见 SecretRedaction.ts 与 StepTrace.tsredactSensitiveComponentValuesForLogs将isSensitive true的参数/返回值替换为WORKFLOW_LOG_REDACTED_VALUE [REDACTED]redactSecretValues递归地扫描结构化追踪数据把 secret 工作流变量的内容从键名和值中一并抹除secret 可能被替换进 JSON 属性名例如 HTTP 头名称因此只清值不清键仍会泄露truncateTraceValue字符串按MAX_TRACE_VALUE_LENGTH 4000截断结构化对象按 JSON 序列化长度判断超限时整体替换为截断串避免“看起来像数据却无法解析”的半截 JSON。RunWorkflow.cleanLogs会在每次落盘前用当前作用域内全部 secret 变量的值对日志与 stepTrace 做同样的清洗。此外secret 值在替换列表中按“最长优先”排序避免短 secret 提前替换而把长 secret 的尾巴暴露在日志里。从 Builder 启动运行在Builder画布编辑器中点击运行会直接打开同一个视图并实时跟随该 run你可以边跑边看而不必等结束后再去找它。常见问题排查我的工作流没有运行按顺序检查确认工作流是 Enabled 状态在它的Overview页面检查。新工作流默认是禁用的而禁用状态会拒绝一切运行——包括手动运行。源码佐证QueueWorkflow.addWorkflowToQueue在入队前会读取isEnabled为 false 时直接抛出BadDataException(This workflow is not enabled)RunWorkflow.runWorkflow在恢复一个被 Sleep 挂起的 run 时也会检查isEnabled若中途被禁用则取消运行并置为Error。OneUptime 事件触发器确认事件确实发生了。打开对应记录并检查其历史。Webhook 触发器确认对端系统正在向正确的 URL 发送请求。大多数工具都会在发送 webhook 时记录日志——去那里核对。调度触发器确认 cron 表达式与你期望的时间匹配。调度注册时若 cron 无法解析QueueWorkflow会创建一条Error状态的日志行内容包含具体错误见resolveScheduleCron。如果 run 确实出现了但状态是Execution Exceeded Current Plan说明项目 30 天运行额度已用完或订阅未缴费。该 run 的日志会写明当前计数与你的套餐上限。此逻辑位于 QueueWorkflow.ts 的addWorkflowToQueue它统计最近 30 天该项目的WorkflowLog条数与WorkflowPlan[plan]对比超出或订阅欠费时创建WorkflowCountExceeded日志并直接 return不再入队。此项仅适用于 OneUptime Cloud。后面的块一直没执行一个没跑的块通常是连线wiring问题。打开Builder检查前一个块的输出是否真的连到了这个块的输入前一个块走的是不是与你预期不同的输出——走了Error而不是Success或No而不是YesSteps 标签会显示它实际走的端口。某个变量传过来是空的打开该 run看失败步骤的Received区域如果看到字面量{{local.components.…}}文本说明引用没有被解析。通常是因为组件 id 或返回值 id 拼写错误——注意要用块的Identifier而不是块上显示的名称。同时检查local.components本身的拼写{{local.componets.api-get-1.returnValues.response-body}}会被当作字面文本发送且 run 仍然报告Executed因为未解析的引用不会抛错。如果看到空字符串说明前一个块执行了但没有产生该字段。源码层面RunWorkflow.getComponentArguments通过VMAPI.replaceValueInPlace做变量替换无法解析的{{...}}会被原样保留。随后logUnresolvedReferences会把每个“进去时是引用、出来后仍是原文本”的表达式检测出来在日志中写入一行警告Warning: {{local.componets.api-get-1.returnValues.response-body}} in 参数名 did not resolve to anything and was left as literal text. Check the step id and the return value name.这就是文档所说的Full Log 标签会携带一行警告点名未解析的引用通常是最快的定位方式。检测逻辑比较的是替换前的输入而非输出文本因此一个“恰好解析成带花括号内容”的正常值不会被误报。手动运行可以触发器运行不行打开Builder点击Run Workflow用模拟真实触发器会发送的字段值填充触发器字段。然后把这次运行的Received值与真实触发那次运行的Received值并排对比。差异通常只是某个字段名或类型不一致。如何重新运行一个工作流没有 retry this run 按钮。系统不会自动重放旧的执行记录因为副作用Slack 消息、API 调用、工单重复执行可能不安全。要重做工作修复工作流让下一次真实触发去驱动它或打开Builder用相同参数点击Run Workflow。Run 保留多久OneUptime Cloudrun 保留30 天之后被删除——这就是为什么两个运行列表都自称“覆盖最近 30 天”。自托管部署run 会一直保留直到你手动删除。如果某个工作流运行非常频繁、把历史刷得很乱可以禁用或删除它停止继续产生噪音。另外在步骤追踪step tracing功能上线之前记录的 run 没有 Steps 内容只能看到 Full Log。源码印证parseTrace对读不出来的追踪数据永远返回空 trace 而不抛错——旧版本写入的行、或由旧构建写入的行都会退化为只显示原始日志。进一步阅读Configuration Safety —— 超时、递归限制、隐藏 secretVariables —— 块中使用的变量语法Components —— 每个块产生什么。相关源码入口RunWorkflow.ts执行器与状态机、QueueWorkflow.ts入队、计划限制与恢复调度、WorkflowLog.ts日志模型、StepTrace.ts步骤追踪结构与 100 步上限、SecretRedaction.ts脱敏实现。【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考