编程语言编译器云原生语言运行时【免费下载链接】wingA programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡项目地址https://gitcode.com/gh_mirrors/wi/wing点击查看免费下载cloud.Service是 Wing 标准库中用于定义长运行服务的核心资源而“令牌Token”则是 Wing 在编译期无法解析、必须到运行时才能确定的值例如 API 的 URL。本文以 tools/hangar/snapshots/test_corpus/sdk_tests/service/tokens.test.w_test_sim.md 这份 Hangar 测试快照为核心线索深入拆解 Wing 的 Service 资源如何在sim模拟器目标下自动“绑定并使用令牌”并还原其背后cloud.Service、util.waitUntil、令牌解析机制与 Sandbox 沙箱进程的完整实现链路。一、这份快照文档到底在记录什么先看这份快照的完整原文# [tokens.test.w](https://link.gitcode.com/i/8edfcd4c0a5d1b33a81f7d15f21488bd) | test | sim ## stdout.log log pass ─ tokens.test.wsim » root/Default/test:will bind and use tokens Tests 1 passed (1) Snapshots 1 skipped Test Files 1 passed (1) Duration DURATION它由三部分构成 1. **标题行**tokens.test.w | test | sim指明被测源文件是仓库中的 [tests/sdk_tests/service/tokens.test.w](https://link.gitcode.com/i/08063e2d2c1326fafffc4e967c0c663a)执行方式是 wing test目标平台是 sim。 2. **stdout.log 代码块**记录了该测试在模拟器中的标准输出。核心一行是 pass ─ tokens.test.wsim » root/Default/test:will bind and use tokens表示名为 “will bind and use tokens” 的测试用例**通过pass**。 3. **统计信息**Tests 1 passed (1)、Snapshots 1 skipped、Test Files 1 passed (1)、Duration DURATION。其中 Duration 被替换为占位符 DURATION这是 Hangar 快照“规范化sanitize”机制的产物。 ### 快照的生成机制 这份快照不是手写的而是由 [tools/hangar/src/utils.ts](https://link.gitcode.com/i/5856c7ff44000d5500ede71577b634df) 中的 createMarkdownSnapshot() 函数自动生成的 ts const snapPath join( snapshotDir, test_corpus, dirname(relativePath), ${wingFile}_${testCase}_${target}.md ); let md # ${wingFile}}/${wingFile}) | ${testCase} | ${target}\n\n;它会把运行结果按test_corpus/目录/文件名_用例_目标.md的约定落到快照目录并在标题中内嵌指向源码文件的相对链接——这就是快照第一行../../../../../../tests/sdk_tests/service/tokens.test.w的来源。由于快照生成时会对输出做规范化处理见下真正的测试文件位于tests/sdk_tests/service/目录读者应前往该目录查看被测代码原文。DURATION占位符与输出的确定性Hangar 为了保证快照跨平台、跨机器稳定可比在 sanitizeOutput() 中做了一系列输出清洗统一换行符、把 Windows 反斜杠替换为正斜杠去掉 Rust 源码中的行列号src/xxx.rs:LINE:COL、绝对堆栈路径把Duration 1m12.3s这类耗时统一替换为Duration DURATION端口号、IP 地址、时间戳等易变内容分别替换为PORT、IP:PORT、TIMESTAMP。这就是快照中Duration DURATION的由来只有耗时被抹平测试断言本身pass/失败才具备稳定的可比较价值。二、被测源码Service 如何“绑定并使用令牌”快照指向的被测文件是 tests/sdk_tests/service/tokens.test.w其完整内容如下bring cloud; bring util; bring http; // only supported in the sim target for now if target sim { let b new cloud.Bucket(); let api new cloud.Api(); api.get(/, inflight () { return { body: api test, status: 200 }; }); let s new cloud.Service(inflight () { let result http.get(api.url); b.put(service.txt, result.body); }); test will bind and use tokens { util.waitUntil(inflight () { return b.exists(service.txt); }); assert(b.get(service.txt) api test); } }这段代码包含了三个互相咬合的关键点target sim条件编译文件开头就明确注明“目前仅sim目标支持only supported in the sim target for now”所以整个测试体被包在目标判断里只有以-t sim运行时才会生效。Service 的 inflight handler 中使用api.urlapi.url是一个典型的令牌token——API 的真实地址只有在模拟器启动、端口分配之后才能确定编译期无法知晓。Service 在启动时执行http.get(api.url)并把响应体写入 Bucket。测试用例本身不直接“驱动” Servicetest will bind and use tokens只是用util.waitUntil轮询 Bucket 里是否出现了service.txt一旦出现就断言其内容等于api test。Service 是自动启动autoStart 默认 true并在后台运行的测试靠“轮询结果”来验证整条链路是否打通。这正是测试名 “will bind and use tokens” 的含义Service 的 inflight 代码“绑定”了api.url这个令牌并在运行时“使用”它成功发起了 HTTP 请求。为什么要用 waitUntil 轮询而不是直接断言因为 Service 的 handler 是异步、后台执行的测试无法预知它何时完成第一次 HTTP 请求与 Bucket 写入。util.waitUntil提供了确定性的等待语义。它的实现在 packages/winglang/sdk/src/util/util.ts 的Util.waitUntil静态方法中public static async waitUntil( predicate: IPredicateHandler, props: WaitUntilProps {}, ): Promiseboolean { const timeout props.timeout ?? Duration.fromMinutes(1); const interval props.interval ?? Duration.fromSeconds(0.1); const f predicate as any; let elapsed 0; while (elapsed timeout.seconds) { if (await f()) { return true; } elapsed interval.seconds; await this.sleep(interval); } if (props.throws ! false) { throw new Error(Timeout elapsed); } return false; }其行为要点对应 WaitUntilProps 接口参数默认值说明timeout1 分钟轮询总超时超过后抛出Timeout elapsed错误interval0.1 秒两次轮询之间的间隔throwstrue超时后是否抛错传false则改为返回布尔值实现上注意超时统计只累加间隔时长不把谓词本身的执行耗时计入源码注释明确提到这一点因此谓词应保持轻量。测试中谓词b.exists(service.txt)刚好是这种轻量检查。三、令牌机制编译期无法解析的值运行时才落地“绑定并使用令牌”的底层支撑是 Wing SDK 的令牌解析器Token Resolver体系定义在 packages/winglang/sdk/src/core/tokens.tsexport interface ITokenResolver { isToken(value: any): boolean; // 判断一个值是否为令牌 lift(value: any): string; // 把一个令牌提升到 inflight 上下文 onLiftValue(host: IInflightHost, value: any): void; // 把令牌绑定到宿主宿主即 Function/Service 等 inflight host }其设计思路源码注释原话“Tokens values are captured as environment variable, and resolved through the compilation target token mechanism.”——令牌值会被“捕获”为环境变量再通过各编译目标的令牌机制解析。环境变量名由 tokenEnvName() 生成export function tokenEnvName(value: string): string { return WING_TOKEN_${value .replace(/([^a-zA-Z0-9])/g, _) .replace(/_$/, ) .replace(/^_/, ) .toUpperCase()}; }即把令牌字符串中非字母数字的字符替换为下划线并转大写前缀WING_TOKEN_。sim 目标如何解析令牌针对本快照使用的sim目标令牌解析器实现在 packages/winglang/sdk/src/target-sim/tokens.ts 的SimTokens类中isToken对字符串值用SIMULATOR_TOKEN_REGEX正则判断是否是模拟器令牌lift把令牌提升为运行时表达式process.env[WING_TOKEN_...]即从进程环境变量读取onLiftValue把令牌以WING_TOKEN_规范化名为键写入宿主的addEnvironment让 inflight 代码在子进程里能通过环境变量拿到真实值。对照而言Terraform 类目标如tf-aws在 packages/winglang/sdk/src/shared-tf/tokens.ts 中走另一条路令牌本质是 CDKTF 的未解析 Tokenlift生成JSON.parse(process.env[WING_TOKEN_...])onLiftValue则用Fn.jsonencode(value)把值编码成环境变量注入宿主当前实现限定宿主必须是Function。这正好呼应了测试文件里那句“目前仅 sim 目标支持”的注释——令牌绑定到 Service 宿主的路径在不同目标下能力并不一致。四、Service 的绑定链路从 inflight 代码到模拟器沙箱抽象基类 cloud.Servicepackages/winglang/sdk/src/cloud/service.ts 定义了cloud.Service的抽象契约构造签名new cloud.Service(handler: IServiceHandler, props?: ServiceProps)ServiceProps两个可选字段env环境变量默认无与autoStart是否自动启动默认true——这正是测试用例里 Service 后台自动运行的来源inflight 接口IServiceClient提供三个方法start()、stop()、started()。抽象基类的_preSynthesize()service.ts#L113-L144会生成服务入口代码并写入workdir下的assetName.cjs文件同时执行关键的一步Lifting.lift(this.handler, this, [handle]);即把 handler 的 inflight “handle” 方法提升到 Service 宿主上——测试中api.url令牌之所以能被“绑定”到 Service就是通过这套 lift 机制把令牌值写入 Service 的环境变量。模拟器目标 Servicepackages/winglang/sdk/src/target-sim/service.ts 是 sim 目标下的具体实现它把绑定结果转成模拟器资源描述const props: ServiceSchema { environmentVariables: this.env, sourceCodeFile: relative(App.of(this).outdir, this.entrypoint), autoStart: this.autoStart, }; return { type: cloud.SERVICE_FQN, props, policy, };environmentVariables正是SimTokens.onLiftValue写入的那些WING_TOKEN_*环境变量schema 定义见 target-sim/schema-resources.ts#L78-L85。模拟器运行时Sandbox 子进程packages/winglang/sdk/src/target-sim/service.inflight.ts 负责真正的运行时行为init()若autoStart为 true则立刻调用start()——这是测试中 Service 在后台自动跑起来的直接原因start()创建Sandbox子进程packages/winglang/sdk/src/shared/sandbox.ts并把环境变量连同WING_SIMULATOR_URL、WING_SIMULATOR_CALLER注入子进程然后调用沙箱的start入口stop()/started()对应停止与状态查询cleanup()测试结束、模拟器回收资源时调用stop()做清理。Sandbox 的核心机制sandbox.ts#L218-L323 的call()是父进程通过child_process.fork()拉起一个 Node 子进程把{ fn, args }消息发过去子进程执行exportsfn后回传{ type: ok, value }或{ type: error, reason }若调用超时默认无超时除非显式传入timeout或进程异常退出则杀死子进程并拒绝 Promise。于是整条链路闭环了api.url编译期令牌 └─ SimTokens.onLiftValue → WING_TOKEN_* 环境变量写入 Service └─ Service.toSimulator → ServiceSchema.environmentVariables └─ service.inflight.ts start() → Sandbox 子进程注入 env └─ inflight handler 中 http.get(process.env[WING_TOKEN_...]) └─ 请求模拟器内 API → 写入 Bucket → waitUntil 轮询命中 → 断言通过五、从快照回推 Hangar 测试运行器Hangartools/hangar是 Wing 仓库的测试运行器它把tests/sdk_tests/**/*.test.w等语料跑在多个目标上并生成上述快照。以错误用例为例tools/hangar/src/error.test.ts 展示了通用运行模式const platforms [sim]; const args [test]; const out await runWingCommand({ cwd: tmpDir, wingFile: relativeWingFile, platforms, args, expectFailure: true, });底层通过 runWingCommand() 调用 wing CLIconst out await execa( wingBin, [ --no-update-check, --no-analytics, ...options.args, // 即 [test] options.wingFile ?? , // 被测 .w 文件 ...platformOptions, // 即 [-t, sim] ], ... );也就是说执行tokens.test.w的快照对应命令等价于wing --no-update-check --no-analytics test tests/sdk_tests/service/tokens.test.w -t sim而Test Files 1 passed (1)这类汇总行就是wing test在模拟器目标下的测试框架输出Snapshots 1 skipped表示快照比对跳过由 Hangar 的快照策略控制Tests 1 passed (1)则确认用例本身全部通过。读者如需复现可在本仓库根目录安装依赖后对上述wing命令自行验证命令基于 utils.ts 中wingBin解析出的本地 CLI 路径。六、可迁移的实战要点这份快照连同其测试代码为在 Wing 中编写“Service 异步执行 令牌依赖”的用例提供了可直接迁移的范式令牌依赖要放到运行时验证像api.url、资源 ARN 这类编译期未知的值正确姿势是让 inflight 代码“绑定”它再用端到端断言验证运行时行为——测试名 “will bind and use tokens” 本身就是这个意图的注释。异步结果用util.waitUntil收敛后台进程的产物本例是 Bucket 文件不应靠固定sleep等待而应轮询直到出现或超时记得throws默认会在超时抛错适合测试环境直接使用。目标差异要显式声明测试文件用if target sim圈定适用范围并注释说明当前能力边界令牌绑定到 Service 目前仅 sim 目标支持这对多目标仓库的用例组织是一个很好的参照。快照输出应可复现任何 CI 化的快照都应像 Hangar 一样抹平耗时、端口、绝对路径等易变信息DURATION、PORT、ABSOLUTE否则快照会因机器差异频繁误报。需要进一步研究时建议按以下路径深入仓库被测源码tests/sdk_tests/service/tokens.test.w同目录另有 callbacks.test.w、http-server.test.w 等 Service 相关用例可对比Service 抽象契约与 API 文档cloud/service.ts、docs/api/04-standard-library/cloud/service.mdsim 目标实现与沙箱target-sim/service.inflight.ts、shared/sandbox.ts令牌解析器core/tokens.ts、target-sim/tokens.ts、shared-tf/tokens.ts快照生成与运行器tools/hangar/src/utils.ts、tools/hangar/src/error.test.ts。赞分享编程语言编译器云原生语言运行时【免费下载链接】wingA programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡项目地址https://gitcode.com/gh_mirrors/wi/wing点击查看免费下载相关推荐Wing 语言内置测试框架用 wing test 在模拟器与真实云端运行同一套测试Wing 语言内置测试框架用 wing test 在模拟器与真实云端运行同一套测试 Wing 是一门面向云的一体化编程语言其内置的轻量级测试框架围绕 win编程语言编译器云原生语言运行时Wing 语言中的 cloud.Service用 Winglang 定义与管理云上长时运行服务Wing 语言中的 cloud.Service用 Winglang 定义与管理云上长时运行服务 cloud.Service 是 Wing 标准库Wing S编程语言编译器云原生语言运行时Wing 模拟器容器测试全解从 sim.Container 到 hangar 快照的端到端验证Wing 模拟器容器测试全解从 sim.Container 到 hangar 快照的端到端验证 本文围绕 Wing 仓库中 sim.Container 资源在编程语言编译器云原生语言运行时上一篇精通 React 中的 Material UI Select从基础用法到表单集成与高级定制的完整实战指南下一篇使用 dyn Trait 在 Rust 中构建异构数据集合comprehensive-rust 动态分发实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考