SuperAPI AI 工具集

write-workflow-as-code

部署与运维

查看项目

更新于 10-16 04:03

技能介绍

用途

本技能适用于编写或修改 Windmill Workflow-as-Code(WAC)脚本。根据资料说明,WAC 以 Windmill 脚本的形式编写,并采用普通脚本工作流进行部署,它不是 OpenFlow 的 YAML 流程;WAC 文件使用正常的脚本 CLI 工作流,没有单独的 WAC 部署命令。支持的 WAC 编写目标为:导入 windmill-client 的 Bun TypeScript 脚本,以及导入 wmill 的 Python 3 脚本。

文件形态与规则

Bun TypeScript 示例从 windmill-client 导入 task、taskScript、taskFlow、step、sleep、waitForApproval、getApprovalUrls、parallel、workflow,使用 workflow 包裹入口;Python 从 wmill 导入对应名称。规则包括:不要调用 main;Bun TypeScript 应导出 workflow 入口,最好写成 export const main = workflow(async (...) => { ... });Python 必须在 async 顶层函数(通常是 main)上使用 @workflow;task 函数以及 taskScript/task_script 或 taskFlow/task_flow 赋值应定义在模块顶层并使用稳定名称;使用精确的 SDK 名称,不要为 workflow、task、taskScript、taskFlow、step、sleep、waitForApproval、task_script、task_flow、wait_for_approval 起别名,因为 WAC 解析器直接识别这些名称。

检查点与重放模型

父工作流在任何挂起、重试、审批或子任务完成后可能从顶部重新运行,已完成的可持久化步骤会从检查点重放。因此,所有副作用或非确定性值都必须放在持久化的 WAC 边界之后:用 task() / @task() 承载应作为独立子作业运行的重型工作;用 taskScript() / task_script() 调用已有脚本或相对模块文件;用 taskFlow() / task_flow() 调用已有 Windmill 流程;用 step(name, fn) 承载需要被检查点的轻量内联工作;用 sleep(seconds) 实现不占用 worker 的服务端休眠;用 waitForApproval() / wait_for_approval() 实现外部审批挂起。绝不能把 API 调用、数据库写入、通知、随机值、时间戳或不可逆变更直接放在顶层工作流主体中,因为工作流主体可能被重新运行。基于 task 或 step 结果的分支是安全的,因为结果已被检查点;基于当前时间、随机数据、环境读取或外部状态的分支则不安全,除非该值先用 step() 捕获。

任务、步骤与并行

task() / @task() 用于将内联函数变为工作流步骤,TypeScript 中建议赋值给具名顶层 const,Python 中建议使用带 @task() 或 @task 装饰的顶层 async 函数。只有工作流主体才会分发步骤;task 作为单个作业运行,因此在 task 内部调用 task 或 step() 是在该作业中就地进行普通函数调用,没有子作业、没有检查点,其 task 选项(retry、timeout、tag)也不适用;在那里 sleep() 会在作业中等待,而 taskScript() / taskFlow() / waitForApproval()(及其 Python 对应)会抛出错误。要获得独立作业,应从工作流主体依次调用各任务并传递结果。对已有脚本使用 taskScript,对已有流程使用 taskFlow。step() 用于轻量的内联值,需使用稳定、描述性的步骤名,不要动态生成步骤名。并行方面,可先启动 task promise/协程再一起 await,或使用 parallel(items, process, { concurrency: 5 })。只并行化相互独立的步骤,不要在 await 之前读取任务结果。

审批

为审批步骤命名,并在发送前于 step() 内生成其 URL。getApprovalUrls / get_approval_urls 返回绑定到该步骤的 URL,与其内置的 approve/reject 按钮使用相同 URL。一个工作流中有多个审批时,每个审批应有自己的 key,以便每条通知恢复各自的步骤;key 必须唯一,重复使用会抛出错误而不是静默重命名。已铸造的 URL 只在其自身步骤等待审批时才可恢复,其他时刻使用会被拒绝。getResumeUrls() / get_resume_urls() 仍可用,但它会签署随机 nonce,其 URL 不与任何特定审批步骤绑定。selfApproval: false 与 self_approval=False 是 Enterprise 专属审批行为,除非用户要求,否则不要使用。

错误处理

除非用户要求恢复逻辑,否则让任务错误使工作流失败。Python 中围绕 WAC 调用使用 except Exception 是安全的,因为内部挂起继承自 BaseException;避免在工作流代码中使用裸 except;如果用户要求对失败子工作进行恢复,可捕获 wmill 的 TaskError。TypeScript 中避免围绕 WAC SDK 调用的宽泛 try/catch,因为 SDK 在初始分发期间使用内部挂起错误,捕获它可能破坏工作流挂起;若无法避免宽泛捕获,应先重新抛出内部挂起错误再处理业务错误。捕获到的失败无论是来自 task 还是 step(),在运行失败主体的那一轮与重放它的每一轮中读到的内容相同,携带 step_key、child_job_id(step() 没有子作业故该字段缺失)、message,以及 result = {"error": {"name", "message", "stack"?, "extra"?}}。应基于这些字段分支,而不是原始异常类型,因为工作流主体每轮都从顶部重跑,重放会从检查点重建失败,记录之外的任何内容都无法保留。Python 抛出 TaskError;TypeScript 抛出名为 TaskError 的 Error,携带相同字段。不会把内容链到 cause / cause,traceback 位于 result.error.stack,并在步骤失败时打印到作业日志。

元数据同步与预览/运行

wmill-lock.yaml 会跟踪每个条目的内容哈希。编辑脚本内容(尤其是增删 import 或修改 main 参数)会使该哈希失效,导致 .lock、.script.yaml 输入 schema 和哈希行过期。此类编辑后应运行 wmill generate-metadata(限定于所改范围),使解析后的 lock、由 .script.yaml 驱动的自动生成参数 UI 以及 wmill-lock.yaml 都与代码一致;否则会在 git-sync 和 CI 中产生伪差异。它只写本地文件(不是部署),但会重新解析依赖,可能提升未固定版本;默认应先提供该操作并在用户同意后运行,除非项目的 AGENTS.md 选择自动运行元数据。运行后应对比重新生成的 .lock / .script.lock 文件,并告知用户哪些依赖版本发生变化。不带路径参数时,generate-metadata 只重新生成内容哈希漂移的条目;import 会传播,编辑被他人导入的脚本也会标记所有导入方过期。若影响范围超出预期,可运行 wmill generate-metadata --dry-run 查看每个过期条目及原因,再用路径参数或 --strict-folder-boundaries 收窄。若磁盘上的 .lock 与 .script.yaml 已正确、仅需刷新 wmill-lock.yaml 中的哈希,可使用 wmill generate-metadata rehash。在选择命令方面,若用户在有本地编辑时说“运行脚本”“试试”“测试”等,应使用 script preview,不要先推送再运行;仅当用户明确说“运行已部署版本”或没有本地编辑时才用 script run;仅当用户明确要求部署、发布、推送时才用 sync push。wmill script preview 不部署,但仍会执行脚本代码并可能产生副作用;wmill generate-metadata 也不部署,只写本地文件。部署(git push 或 wmill sync push)是唯一会改变远程状态的步骤。可使用 wmill resource-type list --schema 发现可用资源类型。

适用场景与限制

本技能适用于以 Bun TypeScript 或 Python 3 编写、修改 Windmill Workflow-as-Code 脚本的场景,涵盖任务编排、检查点重放、审批、并行、错误处理与元数据同步。资料未提供具体的收费、价格、平台范围或效果承诺等信息,暂未提供。