news 2026/9/14 11:08:35

Windmill PostgreSQL 脚本编写实战指南:从参数绑定到 S3 流式导出

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Windmill PostgreSQL 脚本编写实战指南:从参数绑定到 S3 流式导出

Windmill PostgreSQL 脚本编写实战指南:从参数绑定到 S3 流式导出

【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill

本篇技术指南以 Windmill 官方 AI 编程技能write-script-postgresql(见 SKILL.md)为骨架,系统讲解如何在 Windmill 中编写、调试、部署 PostgreSQL 脚本:包括$1::{type}位置参数与注释命名、wmill script previewwmill script run的正确选用、wmill generate-metadata元数据同步机制,以及(s3object)参数注入与-- s3指令流式导出两个高级场景。读完本文,你将掌握一套可直接落地的 PostgreSQL 脚本开发闭环:本地编写 → 本地预览 → 元数据同步 → 按需部署,并能安全地处理大结果集与文件型入参。

一、Windmill SQL 脚本的基本形态

在 Windmill 中,SQL 脚本(PostgreSQL、MySQL、Snowflake、MSSQL、BigQuery 等)与代码型脚本一样存放在工作区中,并通过同一套 CLI 工具链进行管理。与 Python/TypeScript 脚本必须导出main函数不同,PostgreSQL 脚本的"入口"就是 SQL 语句本身,参数通过占位符注入。

通用脚本原则(参见 script.md)同样适用于 PostgreSQL:

  • 脚本返回值必须是 JSON 可序列化的,后续流程步骤可通过results.step_id引用;
  • 凭据与配置存放在 resource(资源)中并通过参数传入,而非硬编码在脚本里;
  • Windmill 会自动安装依赖,脚本内无需展示安装步骤。

二、PostgreSQL 参数绑定:$n::{type}与注释命名

PostgreSQL 脚本的参数直接在语句中以$1::{type}$2::{type}等位置占位符获取:

SELECT * FROM users WHERE name = $1::TEXT AND age > $2::INT;

其中::{type}是 PostgreSQL 的显式类型转换语法,Windmill 依据该类型声明生成输入表单并完成客户端绑定,TEXTINTBIGINTTIMESTAMPJSONB等均可使用。

为了让参数具备可读的名称(而不是只有$1$2),需要在脚本开头用注释声明参数名,注意只写名称、不写类型(类型已由占位符中的::{type}决定):

-- $1 name1 -- $2 name2 = default_value SELECT * FROM users WHERE name = $1::TEXT AND age > $2::INT;

该示例声明了两个参数:name1(对应$1,类型TEXT)与name2(对应$2,类型INT,默认值default_value)。带默认值的参数在运行时可以省略。命名后,Windmill 的自动生成参数 UI、脚本调度与流程编排中都将以name1name2引用这两个入参,极大提升可维护性。

说明:不同 SQL 方言的占位符语法不同——MySQL/Snowflake 用?,MSSQL 用@P1,BigQuery 用@name,而 PostgreSQL 使用$1$2这种位置参数(见 SKILL.md 中对各方言占位符的说明)。Bash 脚本则使用$1$2的位置参数,PowerShell 用param(...)

三、CLI 工作流:previewrun与部署的正确取舍

脚本写完后,面对wmill script previewwmill script rungit push/wmill sync push这几种操作,官方技能给出了明确的意图判定规则,核心原则是按意图选命令,而非按习惯

命令行为适用场景
wmill script preview <script_path>运行本地文件,不部署默认选择。本地迭代、试运行、验证"能不能跑"时使用
wmill script run <path>运行已部署到工作区的版本用户明确要求"运行已部署的版本"/"运行服务器上的版本",或本地没有正在编辑的脚本
wmill generate-metadata仅重生成本地元数据(.script.yaml.lockwmill-lock.yaml哈希),不部署编辑脚本内容后保持元数据同步
git push/wmill sync push将本地变更部署到工作区用户明确要求部署/发布/推送时

3.1 何时用 preview,何时用 run

当用户说"run the script"、"try it"、"test it"、"does it work"且脚本文件存在本地未提交的编辑时,必须使用wmill script preview不要先把脚本 push 到工作区再用script run验证——push 本身就是一次部署,用未经测试的变更覆盖工作区版本是危险的。

只有满足以下条件之一才使用script run

  • 用户明确说"运行已部署的版本"/"运行服务器上的版本";
  • 本地没有正在编辑的脚本(只是调用一个已存在的脚本)。

wmill sync push只在用户明确要求部署/发布/推送,且 preview 已验证通过后使用。如果用户只说 "run"、"try"、"test",不要触发任何部署动作。

3.2 写完脚本后的测试引导

如果用户原始请求中没有要求测试/运行,写完脚本后用一句话主动提出下一步(例如"要不要我用示例参数跑一下wmill script preview?"),不要抛出一堆选项菜单。

如果用户在原始请求中已经要求测试/运行/试跑,则跳过询问直接执行:

wmill script preview <path> -d '<args>'

参数取值应从脚本声明的参数中推断。注意wmill script preview虽然不部署,但仍会真实执行脚本代码并可能产生副作用,因此仅在用户要求测试/预览(或确认执行是有意为之)时才自行运行。

如果想做可视化预览(在开发页面中打开脚本而不是运行并打印结果),则使用preview技能(见 preview/SKILL.md)。

3.3 用wmill resource-type list --schema发现资源类型

编写需要数据库连接的脚本时,可用以下命令查看当前工作区可用的资源类型及其 schema,以确认连接参数的字段名:

wmill resource-type list --schema

四、保持元数据同步:wmill generate-metadata深度解析

wmill-lock.yaml为每个条目维护一个内容哈希。编辑脚本内容——尤其是新增或删除 import修改main的参数签名——会使哈希失效,导致.lock文件、.script.yaml输入 schema 与哈希记录三者不同步。此时需要运行wmill generate-metadata(限定在你改动的范围上),让解析后的锁文件、由.script.yaml驱动的自动生成参数 UI 以及wmill-lock.yaml与代码保持一致。否则会产生 git-sync 与 CI 中的虚假 diff。

4.1 只写本地文件,不是部署

wmill generate-metadata只写本地文件,不是部署。但它会重新解析依赖,因此可能升级未固定版本的依赖(与从 UI 部署行为一致,属预期而非 bug)。默认策略是:先提出建议,用户同意后再运行,而不是每次编辑后静默执行——除非项目的AGENTS.md明确选择自动运行元数据。无论哪种方式,命令由你来执行,而非用户。运行后应 diff 重新生成的.lock/.script.lock文件,并告知用户哪些依赖版本发生了变化(例如requests 2.31.0 → 2.32.0),以便在部署前发现意外升级——即使在Metadata: auto模式下也要告知,因为这是信息而非确认门槛。要固定版本,就在代码中显式 pin。

4.2 不带路径参数时的行为与依赖传播

不带路径参数运行时,generate-metadata只重新生成内容哈希漂移的条目,而不是全部。import 会传播:编辑一个被其他脚本 import 的脚本,会使所有 import 它的脚本也标记为过期——因此共享模块的一行改动可能触发大量锁文件重新生成(这是设计使然,它们的锁必须反映被 import 的代码)。若影响的文件超出预期,先用 dry-run 排查:

wmill generate-metadata --dry-run

它会列出每个过期条目及原因(content changeddepends on <path>),且不修改任何文件。然后可用路径参数收窄范围:

wmill generate-metadata f/foo # 或使用文件夹边界约束 wmill generate-metadata --strict-folder-boundaries

--strict-folder-boundaries保证本次运行只更新指定文件夹内的条目(要求同时提供文件夹参数),其实现细节可见 generate-metadata.ts,其中定义了--dry-run--strict-folder-boundaries选项以及rehash子命令。

4.3 纯哈希刷新:generate-metadata rehash

如果磁盘上的.lock.script.yaml已经正确,只是wmill-lock.yaml需要刷新哈希(哈希漂移,或引导缺失条目),使用rehash子命令——它从磁盘重新记录哈希,不做后端往返、不改变依赖

wmill generate-metadata rehash

该命令对应源码中的rehashOnly快速路径(见 generate-metadata.ts 中rehashCommandrehashOnly),在返回任何后端调用之前即完成哈希重录。

4.4 三步闭环总结

  1. 编辑脚本(增删 import、改main签名)→ 哈希失效;
  2. 运行wmill generate-metadata(必要时先--dry-run预览,再用路径参数/--strict-folder-boundaries收窄)→ 本地元数据一致;
  3. 用户明确要求部署时,再git pushwmill sync push

五、高级场景一:以(s3object)接收文件型参数

PostgreSQL 脚本的某个参数可以声明为(s3object)类型。此时 Windmill 会为该参数渲染一个S3 文件选择器,运行时自动下载文件,并将其绑定为jsonb参数:

  • Parquet / CSV文件由服务端解码为 JSON 记录数组;
  • JSON / JSONL文件原样透传。

脚本内通过jsonb_to_recordset(或任何jsonbAPI)消费:

-- $1 file (s3object) SELECT * FROM jsonb_to_recordset($1::jsonb) AS r(id INT, name TEXT);

该示例把 S3 中的文件内容(如一个含idname列的 CSV/Parquet)解构成关系表,随后可直接参与 JOIN、WHERE 等常规 SQL 操作。

这一机制在 Windmill 后端有完整的实现支撑:pg_executor.rs(见 pg_executor.rs)中通过materialize_s3object_args对每个(s3object)参数下载文件、调用sql_s3_input::fetch_s3object_as_json_text将其物化为 JSON 文本,并重新绑定为jsonb;当物化发生时空值溢出错误会被改写为更友好的 jsonb 相关错误信息。MySQL、MSSQL、BigQuery、DuckDB 执行器也采用同样的(s3object)物化模式,说明这是 Windmill SQL 脚本的通用能力。

六、高级场景二:-- s3指令流式导出查询结果

对于大结果集,在脚本顶部添加-- s3指令即可将查询结果流式写入 S3,而不是作为脚本返回值在内存中缓冲。Windmill 负责写文件,并把生成的S3Object作为脚本结果返回:

-- s3 prefix=exports/users format=parquet SELECT id, name FROM users;

指令中的所有键均为可选:

含义取值 / 默认值
prefix对象键前缀可选,如exports/users
storage命名的存储配置可选,省略时使用工作区默认存储
format导出格式json(默认)、parquetcsv

使用场景:导出数千万行报表数据、生成下游数仓的 Parquet 分片等。因为行数据直接流式写入 S3,内存占用恒定,不会因结果集过大导致脚本 OOM 或响应体超限;脚本的返回值从"整包数据"变成"一个S3Object引用",非常适合与流程后续步骤或 git-sync 工作流配合。

七、实践要点与源码指引

  • 参数即注释、类型即转换:PostgreSQL 脚本参数一律$n::{type}声明类型,注释行只给名称与默认值,两条规则缺一不可。
  • 本地验证优先:有本地编辑时默认wmill script preview;只有用户点名要跑已部署版本才wmill script run;只有明确要求部署才git push/wmill sync push
  • 元数据即契约:编辑后运行wmill generate-metadata,异常扩散用--dry-run排查、用路径参数或--strict-folder-boundaries收窄、纯哈希刷新用rehash
  • 文件型入参用(s3object):自动文件选择器 + 服务端解码 +jsonb_to_recordset消费,避免在 SQL 中手写文件解析。
  • 大结果集用-- s3:流式直写 S3,返回S3Object而非内存缓冲,prefix/storage/format三键均可选。

想继续深入,可阅读以下仓库文件:

  • 技能原文:write-script-postgresql/SKILL.md
  • 脚本编写总纲(含各语言参数绑定约定):system_prompts/auto-generated/script.md
  • 元数据生成命令实现(--dry-run--strict-folder-boundariesrehash):cli/src/commands/generate-metadata/generate-metadata.ts
  • PostgreSQL 执行器((s3object)物化、jsonb 绑定):backend/windmill-worker/src/pg_executor.rs
  • S3 文件输入物化工具:backend/windmill-worker/src/sql_s3_input.rs
  • 部署与仓库接线说明:wmill sync pushgit push的选择取决于仓库如何接线,详见项目级AGENTS.wmill.md中的Deploying一节(该文件位于部署工作区根目录,非本仓库内置文件)

【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 11:05:15

虚拟机安装 Linux 系统完整图文教程

TL;DR&#xff1a;本文以图文结合的方式&#xff0c;手把手演示如何在虚拟机中安装 Linux 系统。从创建虚拟机、加载系统镜像&#xff0c;到分区配置、用户设置、系统安装与重启登录&#xff0c;再到切换中文与安装串口工具 minicom&#xff0c;全程约 10 分钟即可完成&#xf…

作者头像 李华
网站建设 2026/9/14 11:05:09

STM32 蜂鸣器驱动:CubeMX 配置与代码实现

文章目录1. 引言2. 硬件原理3. CubeMX 引脚配置4. 驱动代码实现4.1 头文件 fmq.h4.2 源文件 fmq.c5. 应用示例5.1 多任务互斥保护6. 常见问题与排查6.1 蜂鸣器不响6.2 声音异常&#xff08;音量小或音调不对&#xff09;6.3 误触发&#xff08;上电即响或异常鸣叫&#xff09;7…

作者头像 李华
网站建设 2026/9/14 11:04:25

SpringBoot2+Vue3校园美食分享平台开发实战:从技术选型到部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华