拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Cloudflare Workers RPC 兼容性标志 `rpc_params_dup_stubs`:修复参数内嵌 Stub 的所有权转移语义

Cloudflare Workers RPC 兼容性标志rpc_params_dup_stubs修复参数内嵌 Stub 的所有权转移语义【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs本文讲解 Cloudflare Workers 文档仓库 src/content/compatibility-flags/rpc-params-dup-stubs.md 所记录的兼容性标志rpc_params_dup_stubs它如何改变 RPC 调用参数中内嵌 stub 的所有权语义修复与 Capn Web 的兼容性问题并解决「代理调用导致 stub 被重复 dispose」「Durable Object 回调订阅失效」这两类经典故障。读完本文你将理解 Workers RPC stub 的生命周期规则、dup()的正确使用场景并能据此在自己的 Worker 中正确配置该标志。背景Workers RPC 中的 Stub 与所有权模型Cloudflare Workers 内置了 JavaScript 原生的远程过程调用RPC系统允许同一 Cloudflare 账户下的多个 Worker 通过 Service Bindings 直接互调方法也可以调用声明了绑定的 Durable Object 上的公共方法见 RPC 系统总览。RPC 的参数与返回值几乎可以是所有 Structured Cloneable 类型此外还额外支持函数、继承自RpcTarget的类实例、ReadableStream/WritableStream、Request/Response以及——来自第三个 Worker 的 RPC stub 本身。当你在 RPC 中传递一个函数或一个RpcTarget类实例时对象本身并不会被序列化传输而是被替换为一个指向远端对象的stub。接收方调用该 stub实际上就是在发起一次回到对象原始创建位置的 RPC。stub 背后占用着远端 isolate 中的资源只要 stub 仍然存在对应的远端对象就无法被垃圾回收。由于每个 isolate 拥有各自独立的垃圾收集器调用方必须向远端显式发送信号告知该对象可以被回收——这一过程称为dispose处置stub。在 RPC 生命周期文档中可以看到RPC 系统会在以下几种情况下自动 dispose stub事件处理器执行上下文结束时fetch()处理器返回最终 HTTP 响应、或 RPC 被调用的方法返回后本次事件内创建的所有 stub 都会被自动 dispose。执行上下文可以通过ctx.waitUntil()延长。RPC 调用返回时作为参数接收到的 stub在调用返回后会被自动 dispose。若想保留更长时间必须调用其dup()方法。dispose 返回对象时RPC 返回的任何对象都会被系统附加一个 disposerdispose 该对象即会 dispose 其中包含的所有 stub。其中第二条「callee 收到的参数 stub 在调用返回时被自动 dispose」正是本文主角兼容性标志所要调整的规则。问题根源两条所有权规则叠加造成的重复 dispose原文档指出当 Workers RPC 系统 首次推出时内嵌在某个调用的参数或返回值中的 RPC stub其所有权会被转移也就是说原始 stub 被隐式地 dispose而一个副本被投递给目标方。这条「所有权转移」规则与前述「callee 收到的参数 stub 在调用返回时自动 dispose」规则组合在一起会产生一个棘手的故障如果你**代理proxy**一个调用——即某个 RPC 的实现只是把收到的参数原样传给另一个 RPC 调用——那么参数中的任何 stub 都会被dispose 两次。第一次 dispose 来自「所有权转移」原始 stub 因所有权移交而被隐式处置第二次 dispose 则发生在代理层调用返回时因为接收到的参数 stub 会被自动处置。更糟糕的是如果 stub 的最终接收方希望在调用结束之后保留一个副本这种双重 dispose 会导致代理层中的副本无论如何都会被处置从而断开连接。需要特别指出的是这条问题规则与 lifecycle.mdx 中的 forward 示例 所描述的正常转发场景并不矛盾——dup()机制本身正是为了解决「既要转交、又要自留」的矛盾而存在的而本文标志处理的是纯传递场景下所有权转移本身就不应该发生这一语义问题。解决方案rpc_params_dup_stubs标志的语义针对上述问题Cloudflare 的纯 JavaScript Capn Web 实现率先做出调整RPC 参数中的 stub 不再转移所有权而是被简单地复制duplicate。rpc_params_dup_stubs这个兼容性标志让 Workers Runtime 内置的 RPC 系统对齐 Capn Web 的这一行为。启用后内嵌在 RPC 调用参数中的 stub 将不再发生所有权转移——原始 stub 保持有效目标方收到的是一份独立副本。项目说明标志名启用rpc_params_dup_stubs反义标志禁用rpc_params_transfer_stubs默认启用日期2026-01-20与enable_date一致影响范围Workers Runtime 内置 RPC 的参数 stub 所有权语义根据该标志的 frontmattersort_date与enable_date均为2026-01-20自 2026 年 1 月 20 日起凡是将compatibility_date设置在这一天或更晚的 Worker 项目都将默认采用新的复制语义。新语义下的预期行为启用rpc_params_dup_stubs后原始 stub 不再被隐式 dispose调用方在传参后仍然保有自己那份 stub 的所有权与有效性所有权不会被悄悄转移走接收方获得独立副本callee 收到的 stub 是一份复制其生命周期仍遵循「调用返回时自动 dispose」的既有规则不再有双重 dispose代理调用中参数 stub 只会在代理层返回时被处置一次最终接收方保留的副本不会因代理层处置而被意外破坏连接。典型修复场景基于 Capn Web 的 Durable Object 回调订阅原文档给出了一个该标志修复的真实高频用例——客户端通过 Capn Web 订阅 Durable Object 的回调客户端应用通过一条 Capn Web WebSocket将一个回调函数传给一个无状态 Worker该无状态 Worker 将收到的回调 stub 经Workers RPC转发给一个Durable ObjectDurable Object 对 stub 调用dup()保存一份副本以便稍后回调客户端、通知其事件。在启用本标志之前这一流程会失败一旦订阅函数subscribe自身返回无状态 Worker 中的 Capn Web stub 就会被 dispose——因为它是某次调用返回的、且没有在无状态 Worker 上下文中被dup()过。于是当 Durable Object 稍后尝试调用订阅回调时会收到Error: RPC stub used after being disposed尽管 Durable Object 已经小心地在自己的这一端执行过dup()仍然无法避免报错。启用rpc_params_dup_stubs后参数中的 stub 不再转移所有权、只做复制代理层无状态 Worker持有的副本在调用返回时被正常处置而 Durable Object 侧dup()出的副本依旧有效订阅回调得以正常触发。正确使用dup()所有权时代的必备技能理解本标志的价值离不开对dup()方法的掌握。RPC 生命周期文档的dup()章节 给出了它的典型用法let stub await env.SOME_SERVICE.getThing(); // 创建一个副本。 let stub2 stub.dup(); // 调用某个会 dispose stub 的函数。 await func(stub); // stub2 仍然有效dup()的语义类似 Unix 同名系统调用它创建一个指向同一目标的新句柄该句柄必须被独立地 dispose。如果 stub 指向的RpcTarget实例带有 disposer只有当所有副本都被 dispose 后disposer 才会被调用。注意同一RpcTarget实例多次经 RPC 传递会各自生成新的 stub这些新 stub不算彼此副本因此每传递一次disposer 就会分别被调用一次。若要避免这一行为可以手动创建 stub 并多次传递——每次传递都需要dup()一份因为传递 stub 时所有权会转移给接收方import { RpcTarget, RpcStub } from cloudflare:workers; class Foo extends RpcTarget { // ... } let obj new Foo(); let stub new RpcStub(obj); await rpc1(stub.dup()); // 发送 stub 的一份 dup await rpc2(stub.dup()); // 再发送另一份 dup stub[Symbol.dispose](); // dispose 原始 stub // 当另外两个副本在远端被 dispose 时 // obj 的 disposer 才会被调用。配合using声明Wrangler v4 原生支持可以显著降低忘记 dispose 的概率using result stub.foo();当result离开作用域时其包含的所有 stub 都会被自动 dispose。若想在using作用域结束后仍保留某个返回的 stub请在作用域结束前对其调用dup()并记得之后显式 dispose 这个副本。如何配置该兼容性标志兼容性标志通过在compatibility_flags中列出来启用或禁用参见 兼容性标志文档通过 Wrangler 配置在 Worker 的 Wrangler 配置文件 的wrangler.jsonc中添加{ compatibility_date: 2026-01-20, compatibility_flags: [ rpc_params_dup_stubs ] }若你希望在新兼容日期2026-01-20或更晚下仍然保留旧的所有权转移行为可以显式加入反义标志{ compatibility_date: 2026-01-20, compatibility_flags: [ rpc_params_transfer_stubs ] }通过 Cloudflare Dashboard / API除 Wrangler 外还可以在 Cloudflare Dashboard 的 Worker 设置中修改兼容性标志或通过 Workers Script API / Workers Versions API 上传 Worker 时在请求体metadata字段中设置compatibility_flags。由于该标志在2026-01-20起已默认启用多数新项目无需显式配置只有需要提前试用或保留旧语义时才需要手动指定。迁移建议与注意事项新项目compatibility_date设置为2026-01-20或更晚即可自动获得新语义无需额外配置。存量项目早于该日期若你依赖「参数 stub 所有权转移」这一旧行为例如依赖调用后原始 stub 自动失效来释放资源升级兼容日期前需评估代码否则建议显式添加rpc_params_transfer_stubs临时保留旧行为或改用dup()显式管理副本生命周期。与using声明的配合无论新旧语义显式资源管理始终是最可靠的做法——在 RPC 调用返回处优先使用using result stub.foo()需要保留时在作用域内dup()。Capn Web 集成场景如果你的架构涉及 Capn Web WebSocket 与 Workers RPC 的混合链路如回调订阅、事件转发请确保参与链路的全部 Worker 均已启用新语义否则仍可能出现跨层 stub 被提前 dispose 的问题。延伸阅读标志原始定义文档本主题的权威来源包含标志名称、启用日期与完整动机说明。Workers RPC 系统总览stub、promise pipelining、转发等 RPC 核心概念。Workers RPC 生命周期自动处置规则、执行上下文、dup()与RpcTargetdisposer 的完整说明。兼容性标志配置指南Wrangler / Dashboard / API 三种配置方式的细节。兼容性日期说明理解compatibility_date如何批量启用兼容性标志。【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门