- 编程语言
- 编译器
- 云原生
- 语言运行时
【免费下载链接】wing
A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
导读
本文以 winglang 仓库 hangar 测试工具生成的快照 pop.test.w_test_sim.md 为线索,完整解读cloud.Queue.pop()在 sim 平台下的测试行为、Queue.timeout配置在 sim 平台不支持的原因,以及 hangar 快照体系的生成机制。读完本文,你将理解 wing 中队列pop()的语义(非 FIFO、消息可见性超时、空队列返回nil),掌握 sim 与 tf-aws 两种平台在队列实现上的根本差异,并能看懂 hangar 快照中unsupported与skipped状态的含义。
快照文件是什么:一次 "不支持" 的测试记录
该快照是 wing 官方 SDK 测试集在 sim 平台上运行pop.test.w后留下的标准输出记录,其内容看似只有一段报错日志,却完整展示了 hangar 快照体系的三种典型状态:运行结果、编译产物、平台能力限制。
快照正文结构如下:
Error: Queue.timeout is not supported on the sim platform yet. For more information see: https://github.com/winglang/wing/issues/1980. Contributions welcome ❤️ --> pop.test.w:5:9 | bring util; | | let timeout = 3s; 5 | let q = new cloud.Queue(timeout: timeout); | ^ at <ABSOLUTE>/pop.test.w:5:9 Tests 1 unsupported (1) Snapshots 1 skipped Test Files 1 unsupported (1) Duration <DURATION>要点逐条解读:
- 错误行号精确到源码位置:
pop.test.w:5:9指向new cloud.Queue(timeout: timeout)这一行,说明编译器/运行时在 preflight 阶段构造队列时就拦截了timeout参数; - 错误文案自述平台限制:"Queue.timeout is not supported on the sim platform yet." 是 SDK 源码中明确抛出的
NotImplementedError(见下文源码章节); <DURATION>是快照归一化占位符:hangar 在生成快照时会归一化随机数与绝对路径(如<ABSOLUTE>),保证快照内容可重复对比;- 统计行:
Tests 1 unsupported (1)表示本文件 1 个测试因平台不支持而跳过;Snapshots 1 skipped表示对应的测试快照未生成。
快照文件名遵循 hangar 的命名约定:{测试文件名}_{用例类型}_{目标平台}.md,即pop.test.w+test(wing test命令)+sim(sim 平台)。同目录下还有一个配对快照 pop.test.w_compile_tf-aws.md,记录的是同一文件在 tf-aws 平台的wing compile产物,二者形成鲜明的跨平台对照。
测试用例源码:pop 的完整语义验证
快照指向的源测试文件是 pop.test.w(快照首行的相对链接../../../../../../tests/sdk_tests/queue/pop.test.w即指向该文件)。完整源码如下:
bring cloud; bring util; let timeout = 3s; let q = new cloud.Queue(timeout: timeout); test "pop" { q.push("Foo", "Bar"); let first = q.pop(); let second = q.pop(); // ensure messages are deleted after timeout util.sleep(timeout); let third = q.pop(); // queue is not FIFO assert(first == "Foo" || first == "Bar"); assert(second == "Foo" || second == "Bar"); assert(third == nil); }该用例一口气验证了pop()的三条核心语义:
| 验证点 | 代码表达 | 含义 |
|---|---|---|
| 按序弹出两条消息 | q.push("Foo", "Bar")后两次q.pop() | 队列可以反复弹出消息,且每条消息只被弹出一次 |
| 非 FIFO 特性 | assert(first == "Foo" \|\| first == "Bar") | cloud.Queue默认不是 FIFO 队列,两条消息被弹出的先后顺序不受保证,因此断言只校验集合成员关系 |
| 消息在超时后被删除 | util.sleep(timeout)后第三次q.pop()返回nil | 队列中已无消息,空队列弹出返回nil(wing 中的可选类型string \| undefined) |
第三条是本用例的精华:Queue.timeout在这里的真正作用是消息可见性/生命周期超时。在 tf-aws 平台,它对应 SQS 的VisibilityTimeout(消费者取走消息后,若在超时内未处理完,消息会重新可见);在本用例中则被用来验证"弹出即删除、超时后队列归空"的行为。
有趣的是,这个测试文件在 sim 平台根本无法运行到test "pop"内部——因为new cloud.Queue(timeout: timeout)这行在 preflight 阶段就直接抛错了。这正是快照呈现"1 unsupported"的原因。
为什么 sim 平台拒绝 timeout:源码证据
错误信息在 SDK 中确实存在,见 target-sim/queue.ts 的构造函数:
constructor(scope: Construct, id: string, props: cloud.QueueProps = {}) { super(scope, id, props); if (props.timeout) { throw new NotImplementedError( "Queue.timeout is not supported on the sim platform yet.", { issue: "https://github.com/winglang/wing/issues/1980", resource: this.constructor.name, operation: "timeout", }, ); } this.timeout = props.timeout ?? Duration.fromSeconds(30); this.retentionPeriod = props.retentionPeriod ?? Duration.fromHours(1); ... }关键信息:
- sim 平台实现类
Queue extends cloud.Queue(即target-sim命名空间下的具体实现); - 只要
props.timeout被显式设置,构造函数就抛出NotImplementedError,并附带 GitHub issue 编号 1980 作为追踪链接(For more information see那行正是该 issue 的渲染来源); - 该限制仅存在于 sim 平台:
QueueProps.timeout是 cloud/queue.ts 中定义的抽象接口属性,默认值 30s,sim 实现只是暂未落地该能力; - sim 实现内部仍会读取
timeout属性用于toSimulator()的 schema 传递与可见性超时逻辑(pushMessagesBackToQueue中this.timeoutSeconds * 1000),说明基础设施已预留,只是显式传参尚未开放。
同类限制在仓库中并非孤例:tests/sdk_tests/queue/timeout.test.w顶部用/*\ skip: true \*/元注释整体跳过,注释中直接引用同一 issue 1980;tests/sdk_tests/queue/retention_period.main.w则用if @target != "sim"运行时条件把 timeout/retention 组合测试排除在 sim 之外。这形成了一个清晰的模式:SDK 测试集中凡是触及 sim 尚不支持的能力,要么用元注释跳过,要么用目标平台条件分流。
跨平台对照:tf-aws 下 timeout 映射为 SQS VisibilityTimeout
与 test 快照配对的是 compile 快照 pop.test.w_compile_tf-aws.md,它记录了同一份pop.test.w在 tf-aws 平台编译生成的 Terraform 配置:
{ "resource": { "aws_sqs_queue": { "Queue": { "//": { "metadata": { "path": "root/Default/Default/Queue/Default", "uniqueId": "Queue" } }, "message_retention_seconds": 3600, "name": "Queue-c822c726", "visibility_timeout_seconds": 3 } } } }对照关系一目了然:
timeout: 3s→visibility_timeout_seconds: 3:Queue.timeout在 AWS 平台被映射为 SQS 队列的可见性超时;message_retention_seconds: 3600:未显式设置retentionPeriod时采用默认值 1 小时(3600 秒);- 资源命名:
Queue-c822c726由资源命名规则生成,80 字符上限、仅允许字母数字与-_(见 target-tf-aws/queue.ts 的NAME_OPTS)。
tf-aws 实现 target-tf-aws/queue.ts 中,visibilityTimeoutSeconds与messageRetentionSeconds的默认值逻辑与抽象接口保持一致(30s / 1h),因此同一份代码在不同平台编译会得到语义一致、实现不同的产物。这也是 hangar 快照体系的核心价值:让跨平台行为差异显式化、可审查。
pop() 的底层实现:sim 随机抽取 vs AWS 原子删除
pop()在 cloud/queue.ts 的抽象接口IQueueClient中定义为:
/** * Pop a message from the queue. * @returns The message, or `nil` if the queue is empty. * @inflight */ pop(): Promise<string | undefined>;两种平台的实现体现了"非 FIFO"这一语义承诺的落地方式:
sim 平台(target-sim/queue.inflight.ts):队列在内存中用 JavaScriptArray承载,pop()通过Math.random()随机下标splice取出消息,天然满足非 FIFO:
public async pop(): Promise<string | undefined> { return this.context.withTrace({ message: `Pop ().`, activity: async () => { // extract a random message from the queue const message = this.messages.splice( Math.floor(Math.random() * this.messages.length), 1, )[0]; return message?.payload; }, }); }AWS 平台(shared-aws/queue.inflight.ts):通过 SQS 的ReceiveMessageCommand取 1 条消息,随即用DeleteMessageCommand删除(依赖ReceiptHandle),从而实现"弹出即删除":
public async pop(): Promise<string | undefined> { const receiveCommand = new ReceiveMessageCommand({ QueueUrl: await this.queueUrl(), MaxNumberOfMessages: 1, }); const data = await this.client.send(receiveCommand); if (!data.Messages || data.Messages.length === 0) { return undefined; // 空队列返回 nil/undefined } const message = data.Messages[0]; if (message.ReceiptHandle) { const deleteCommand = new DeleteMessageCommand({ ... }); await this.client.send(deleteCommand); } return message.Body; }值得注意的是,SQS 标准队列默认即是尽力而为的乱序队列,与cloud.Queue"默认非 FIFO" 的抽象语义严格对应。若需要严格 FIFO,需另行选用目标平台提供的有序队列能力——抽象层不保证顺序。
快照是怎么生成的:hangar 测试流水线
该快照并非手写,而是 hangar(Wing Toolchain Test Suite)自动化生成并校验的产物。理解它的产生过程,就能读懂快照中每一行的由来:
第一步:生成测试描述文件。generate_tests.ts 递归扫描tests/sdk_tests目录下所有.w文件,为每个文件生成一个 vitest 用例:wing compile -t tf-aws和wing test -t sim各一个。pop.test.w因此有了两个测试目标,与两个快照文件一一对应。
第二步:执行并收集输出。generated_test_targets.ts 中的testTest在临时目录运行wing test -t sim,把进程的stdout写入fileMap["stdout.log"];compileTest则运行wing compile -t tf-aws并把生成的main.tf.json及.wing目录下的 preflight/inflight 产物写入fileMap。
第三步:落盘快照。utils.ts 中的createMarkdownSnapshot把fileMap渲染成 Markdown:首行标题携带源文件 | 用例类型 | 目标平台,随后按文件扩展名用代码块包裹各产物。快照路径由 paths.ts 的snapshotDir决定,即tools/hangar/__snapshots__。
第四步:对比校验。快照写入后,后续每次运行测试都会与已提交的快照做toMatchFileSnapshot对比。若 SDK 行为、Terraform 产物或错误文案发生变化而快照未同步更新,CI 会直接失败——这就是快照文件标题中源文件相对链接的用途:方便开发者从快照一键跳回源测试文件核实。
由于pop.test.w在 sim 平台因 timeout 限制无法运行到测试体,testTest只收集到 stdout 中的报错日志,因此快照只有stdout.log一节;而 tf-aws 编译成功,快照则包含完整的main.tf.json。
"1 unsupported / 1 skipped" 的含义与工程启示
快照末行的统计信息是 hangar 对"平台能力不对称"的显式登记:
Tests 1 unsupported (1):本文件的 1 个测试在 sim 平台不可用。根因是 preflight 阶段抛出的NotImplementedError,wing 将其归类为"平台未实现特性"而非"测试失败";Snapshots 1 skipped:未生成对应的成功快照,避免把失败输出误当作基线;Test Files 1 unsupported (1):整个文件在 sim 平台的测试目标被判定为不支持。
这类"unsupported"快照与 unsupported.test.ts 中显式断言"不支持资源须报错"的测试共同构成 wing 的平台能力护栏:抽象的cloud.*资源在各平台落地进度不同时,必须以可预期的错误显式暴露,而不是静默降级。对使用者而言,这意味着在 sim 上调试队列类应用时应避免使用timeout参数;若必须验证可见性超时行为,可以参照tests/sdk_tests/queue/timeout.test.w的方式,用@target条件或元注释在平台间分流,等待 issue 1980 落地。
进一步阅读
- 队列抽象与全部 inflight 方法:cloud/queue.ts
- sim 平台队列实现(含 timeout 限制抛出点):target-sim/queue.ts
- sim 平台队列运行时(随机 pop 与可见性超时回填):target-sim/queue.inflight.ts
- AWS 平台队列实现(SQS 映射):target-tf-aws/queue.ts
- AWS 平台队列客户端(SQS 原子 pop):shared-aws/queue.inflight.ts
- 队列官方参考文档:cloud/queue.md
- 其余队列测试用例:
tests/sdk_tests/queue/下的push.test.w、purge.test.w、timeout.test.w、retention_period.main.w等文件
- 编程语言
- 编译器
- 云原生
- 语言运行时
【免费下载链接】wing
A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
相关推荐
深入解析 Wing 云队列 retentionPeriod:从 Hangar 测试快照到 SDK 多平台实现
深入解析 Wing 云队列 retentionPeriod:从 Hangar 测试快照到 SDK 多平台实现 Wing 语言中的 cloud.Queue 是面向
编程语言编译器云原生语言运行时Wing 云语言 math 标准库 fibonacci 函数实战:从递归实现到 sim 平台测试快照验证
Wing 云语言 math 标准库 fibonacci 函数实战:从递归实现到 sim 平台测试快照验证 导读 本文以 Wing 仓库中 fibonacci.t
编程语言编译器云原生语言运行时Wing 语言 cloud.Queue push 操作实战:从 SDK 源码到 hangar 快照测试(sim 平台)
Wing 语言 cloud.Queue push 操作实战:从 SDK 源码到 hangar 快照测试(sim 平台) Wing 是一门面向云的应用编程语言,
编程语言编译器云原生语言运行时
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考